src/java.net.http/share/classes/java/net/http/WebSocket.java
branchhttp-client-branch
changeset 56318 2a96e88888b2
parent 56263 4933a477d628
child 56320 f82729ca8660
--- a/src/java.net.http/share/classes/java/net/http/WebSocket.java	Sat Mar 17 18:01:01 2018 +0000
+++ b/src/java.net.http/share/classes/java/net/http/WebSocket.java	Sun Mar 18 14:31:36 2018 +0000
@@ -26,7 +26,6 @@
 package java.net.http;
 
 import java.io.IOException;
-import java.net.ProtocolException;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.time.Duration;
@@ -67,12 +66,10 @@
  * {@code WebSocket} will not pass {@code null} arguments to methods of
  * {@code Listener}.
  *
- * @implSpec Methods of {@code WebSocket} are failure-atomic in respect to
- * {@code NullPointerException}, {@code IllegalArgumentException} and
- * {@code IllegalStateException}. That is, if a method throws said exception, or
- * a returned {@code CompletableFuture} completes exceptionally with said
- * exception, the {@code WebSocket} will behave as if the method has not been
- * invoked at all.
+ * <p> The state of a {@code WebSocket} is not changed by the invocations that
+ * throw or return a {@code CompletableFuture} that completes with one of the
+ * {@code NullPointerException}, {@code IllegalArgumentException},
+ * {@code IllegalStateException} exceptions.
  *
  * <p> A {@code WebSocket} invokes methods of its listener in a thread-safe
  * manner.
@@ -211,23 +208,29 @@
     /**
      * The receiving interface of {@code WebSocket}.
      *
-     * <p> A {@code WebSocket} invokes methods on its listener when it receives
-     * messages or encounters events. The invoking {@code WebSocket} is passed
-     * as an argument to {@code Listener}'s methods. A {@code WebSocket} invokes
-     * methods on its listener in a thread-safe manner.
+     * <p> A {@code WebSocket} invokes methods on the associated listener when
+     * it receives messages or encounters events. A {@code WebSocket} invokes
+     * methods on the listener in a thread-safe manner.
      *
      * <p> Messages received by the {@code Listener} conform to the WebSocket
-     * Protocol, otherwise {@code onError} with a {@link ProtocolException} is
-     * invoked.
-     *
-     * <p> Unless otherwise stated if a listener's method throws an exception or
-     * a {@code CompletionStage} returned from a method completes exceptionally,
+     * Protocol, otherwise {@code onError} with a {@link IOException} is invoked.
+     * Any {@code IOException} raised by {@code WebSocket} will result in an
+     * invocation of {@code onError} with that exception. Unless otherwise
+     * stated if a listener's method throws an exception or a
+     * {@code CompletionStage} returned from a method completes exceptionally,
      * the {@code WebSocket} will invoke {@code onError} with this exception.
      *
      * <p> If a listener's method returns {@code null} rather than a
      * {@code CompletionStage}, {@code WebSocket} will behave as if the listener
      * returned a {@code CompletionStage} that is already completed normally.
      *
+     * @apiNote Methods of {@code Listener} have a {@code WebSocket} parameter
+     * which holds an invoking {@code WebSocket} at runtime. A careful attention
+     * is required if a listener is associated with more than a single
+     * {@code WebSocket}. In this case invocations related to different
+     * instances of {@code WebSocket} may not be ordered and may even happen
+     * concurrently.
+     *
      * @since 11
      */
     interface Listener {
@@ -402,7 +405,8 @@
         }
 
         /**
-         * A Close message has been received.
+         * Receives a Close message indicating the {@code WebSocket}'s input has
+         * been closed.
          *
          * <p> This is the last invocation from the {@code WebSocket}. By the
          * time this invocation begins the {@code WebSocket}'s input will have
@@ -415,21 +419,30 @@
          * {@code 1000 <= code <= 65535}. The {@code reason} is a string which
          * has an UTF-8 representation not longer than {@code 123} bytes.
          *
-         * <p> Return a {@code CompletionStage} that will be used by the
-         * {@code WebSocket} as a signal that it may close the output. The
-         * {@code WebSocket} will close the output at the earliest of completion
-         * of the returned {@code CompletionStage} or invoking a
-         * {@link WebSocket#sendClose(int, String) sendClose} method.
-         *
-         * <p> If an exception is thrown from this method or a
-         * {@code CompletionStage} returned from it completes exceptionally,
-         * the resulting behaviour is undefined.
+         * <p> If the {@code WebSocket}'s output is not already closed, the
+         * {@code CompletionStage} returned by this method will be used as an
+         * indication that the {@code WebSocket}'s output may be closed. The
+         * {@code WebSocket} will close its output at the earliest of completion
+         * of the returned {@code CompletionStage} or invoking either of the
+         * {@code sendClose} or {@code abort} methods.
          *
          * @apiNote Returning a {@code CompletionStage} that never completes,
-         * effectively disables the automatic closure of the output.
+         * effectively disables the reciprocating closure of the output.
+         *
+         * <p> To specify a custom closure code and/or reason code the sendClose
+         * may be invoked from inside onClose call:
+         * <pre>{@code
+         *  public CompletionStage<?> onClose(WebSocket webSocket,
+         *                             int statusCode,
+         *                             String reason) {
+         *      webSocket.sendClose(CUSTOM_STATUS_CODE, CUSTOM_REASON);
+         *      return new CompletableFuture<Void>();
+         *  }
+         * }</pre>
          *
          * @implSpec The default implementation of this method returns
-         * {@code null}, signaling that the output may be closed.
+         * {@code null}, indicating that the output should be closed
+         * immediately.
          *
          * @param webSocket
          *         the WebSocket on which the message has been received
@@ -449,7 +462,7 @@
         }
 
         /**
-         * An unrecoverable error has occurred.
+         * An error has occurred.
          *
          * <p> This is the last invocation from the {@code WebSocket}. By the
          * time this invocation begins both {@code WebSocket}'s input and output
@@ -500,10 +513,8 @@
     /**
      * Sends a Text message with characters from the given {@code CharSequence}.
      *
-     * <p> To send a Text message invoke this method only after the previous
-     * Text or Binary message has been sent. The character sequence must not be
-     * modified until the {@code CompletableFuture} returned from this method
-     * has completed.
+     * <p> The character sequence must not be modified until the
+     * {@code CompletableFuture} returned from this method has completed.
      *
      * <p> A {@code CompletableFuture} returned from this method can
      * complete exceptionally with:
@@ -513,7 +524,7 @@
      *          or if a previous Binary message has been sent with
      *          {@code isLast == false}
      * <li> {@link IOException} -
-     *          if an I/O error occurs
+     *          if an I/O error occurs, or if the output is closed
      * </ul>
      *
      * @implNote If a partial or malformed UTF-16 sequence is passed to this
@@ -534,11 +545,10 @@
     /**
      * Sends a Binary message with bytes from the given {@code ByteBuffer}.
      *
-     * <p> To send a Binary message invoke this method only after the previous
-     * Text or Binary message has been sent. The message consists of bytes from
-     * the buffer's position to its limit. Upon normal completion of a
-     * {@code CompletableFuture} returned from this method the buffer will have
-     * no remaining bytes. The buffer must not be accessed until after that.
+     * <p> The message consists of bytes from the buffer's position to its
+     * limit. Upon normal completion of a {@code CompletableFuture} returned
+     * from this method the buffer will have no remaining bytes. The buffer must
+     * not be accessed until after that.
      *
      * <p> The {@code CompletableFuture} returned from this method can
      * complete exceptionally with:
@@ -548,7 +558,7 @@
      *          or if a previous Text message has been sent with
      *              {@code isLast == false}
      * <li> {@link IOException} -
-     *          if an I/O error occurs
+     *          if an I/O error occurs, or if the output is closed
      * </ul>
      *
      * @param message
@@ -573,10 +583,12 @@
      * <p> The {@code CompletableFuture} returned from this method can
      * complete exceptionally with:
      * <ul>
+     * <li> {@link IllegalStateException} -
+     *          if the previous Ping or Pong message has not been sent yet
      * <li> {@link IllegalArgumentException} -
      *          if the message is too long
      * <li> {@link IOException} -
-     *          if an I/O error occurs
+     *          if an I/O error occurs, or if the output is closed
      * </ul>
      *
      * @param message
@@ -598,10 +610,12 @@
      * <p> The {@code CompletableFuture} returned from this method can
      * complete exceptionally with:
      * <ul>
+     * <li> {@link IllegalStateException} -
+     *          if the previous Ping or Pong message has not been sent yet
      * <li> {@link IllegalArgumentException} -
      *          if the message is too long
      * <li> {@link IOException} -
-     *          if an I/O error occurs
+     *          if an I/O error occurs, or if the output is closed
      * </ul>
      *
      * @param message
@@ -613,8 +627,8 @@
     CompletableFuture<WebSocket> sendPong(ByteBuffer message);
 
     /**
-     * Sends a Close message with the given status code and the reason,
-     * initiating an orderly closure.
+     * Initiates an orderly closure of this {@code WebSocket}'s output by
+     * sending a Close message with the given status code and the reason.
      *
      * <p> The {@code statusCode} is an integer from the range
      * {@code 1000 <= code <= 4999}. Status codes {@code 1002}, {@code 1003},
@@ -623,29 +637,33 @@
      * status codes is implementation-specific. The {@code reason} is a string
      * that has an UTF-8 representation not longer than {@code 123} bytes.
      *
-     * <p> Use the provided integer constant {@link #NORMAL_CLOSURE} as a status
-     * code and an empty string as a reason in a typical case.
-     *
      * <p> A {@code CompletableFuture} returned from this method can
      * complete exceptionally with:
      * <ul>
      * <li> {@link IllegalArgumentException} -
      *          if {@code statusCode} is illegal
      * <li> {@link IOException} -
-     *          if an I/O error occurs
+     *          if an I/O error occurs, or if the output is closed
      * </ul>
      *
-     * <p> By the time the {@code CompletableFuture} returned from this method
-     * completes normally, the output will have been closed.
+     * <p> Unless the {@code CompletableFuture} returned from this method
+     * completes with {@code IllegalArgumentException}, or the method throws
+     * {@code NullPointerException}, the output will be closed.
+     *
+     * <p> If not already closed, the input remains open until it is
+     * {@linkplain Listener#onClose(WebSocket, int, String) closed} by the server,
+     * or {@code abort} is invoked, or an
+     * {@linkplain Listener#onError(WebSocket, Throwable) error} occurs.
      *
-     * @implSpec An endpoint sending a Close message might not receive a
-     * complementing Close message in a timely manner for a variety of reasons.
-     * The {@code WebSocket} implementation is responsible for providing a
-     * closure mechanism that guarantees that once {@code sendClose} method has
-     * been invoked the {@code WebSocket} will close regardless of whether or
-     * not a Close frame has been received and without further intervention from
-     * the user of this API. Method {@code sendClose} is designed to be,
-     * possibly, the last call from the user of this API.
+     * @apiNote Use the provided integer constant {@link #NORMAL_CLOSURE} as a
+     * status code and an empty string as a reason in a typical case
+     * <pre>{@code
+     *     CompletableFuture<WebSocket> webSocket = ...
+     *     webSocket.thenCompose(ws -> ws.sendText("Hello, ", false))
+     *              .thenCompose(ws -> ws.sendText("world!", true))
+     *              .thenCompose(ws -> ws.sendClose(WebSocket.NORMAL_CLOSURE, ""))
+     *              .join();
+     * }</pre>
      *
      * @param statusCode
      *         the status code
@@ -681,8 +699,7 @@
     String getSubprotocol();
 
     /**
-     * Tells whether or not this {@code WebSocket} is permanently closed
-     * for sending messages.
+     * Tells whether this {@code WebSocket}'s output is closed.
      *
      * <p> If this method returns {@code true}, subsequent invocations will also
      * return {@code true}.
@@ -692,8 +709,7 @@
     boolean isOutputClosed();
 
     /**
-     * Tells whether or not this {@code WebSocket} is permanently closed
-     * for receiving messages.
+     * Tells whether this {@code WebSocket}'s input is closed.
      *
      * <p> If this method returns {@code true}, subsequent invocations will also
      * return {@code true}.
@@ -703,15 +719,11 @@
     boolean isInputClosed();
 
     /**
-     * Closes this {@code WebSocket} abruptly.
+     * Closes this {@code WebSocket}'s input and output abruptly.
      *
      * <p> When this method returns both the input and the output will have been
-     * closed. Subsequent invocations will have no effect.
-     *
-     * @apiNote Depending on its implementation, the state (for example, whether
-     * or not a message is being transferred at the moment) and possible errors
-     * while releasing associated resources, this {@code WebSocket} may invoke
-     * its listener's {@code onError}.
+     * closed. Any pending send operations will fail with {@code IOException}.
+     * Subsequent invocations of {@code abort()} will have no effect.
      */
     void abort();
 }