# HG changeset patch # User prappo # Date 1521651025 0 # Node ID 58e16ad3fb9824d91e6a7d00c1ae5b2a3c5a5819 # Parent 7f921a5a6e104432d223da3650ad9b0d68876240 http-client-branch: (WebSocket) almost missed the CSR train diff -r 7f921a5a6e10 -r 58e16ad3fb98 src/java.net.http/share/classes/java/net/http/HttpClient.java --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java Wed Mar 21 16:30:10 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java Wed Mar 21 16:50:25 2018 +0000 @@ -580,9 +580,6 @@ * CompletableFuture ws = client.newWebSocketBuilder() * .buildAsync(URI.create("ws://websocket.example.com"), listener); } * - *

A {@code WebSocket.Builder} returned from this method is not safe for - * use by multiple threads without external synchronization. - * * @implSpec The default implementation of this method throws * {@code UnsupportedOperationException}. Clients obtained through * {@link HttpClient#newHttpClient()} or {@link HttpClient#newBuilder()} diff -r 7f921a5a6e10 -r 58e16ad3fb98 src/java.net.http/share/classes/java/net/http/WebSocket.java --- a/src/java.net.http/share/classes/java/net/http/WebSocket.java Wed Mar 21 16:30:10 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/WebSocket.java Wed Mar 21 16:50:25 2018 +0000 @@ -102,7 +102,7 @@ int NORMAL_CLOSURE = 1000; /** - * A builder for creating {@code WebSocket} instances. + * A builder of {@code WebSocket} instances. * *

To obtain a {@code WebSocket} configure a builder as required by * calling intermediate methods (the ones that return the builder itself), @@ -110,7 +110,8 @@ * an appropriate default value (or behavior) will be assumed. * *

Unless otherwise stated, {@code null} arguments will cause methods of - * {@code Builder} to throw {@code NullPointerException}. + * {@code Builder} to throw {@code NullPointerException}. A {@code Builder} + * is not safe for use by multiple threads without external synchronization. * * @since 11 */ @@ -246,7 +247,7 @@ *

This is the initial invocation and it is made once. It is * typically used to make a request for more invocations. * - * @implSpec The default implementation of this method behaves as if: + * @implSpec The default implementation is equivalent to: * *

{@code
          *     webSocket.request(1);
@@ -265,7 +266,7 @@
          * {@code CharSequence}. Do not access the {@code CharSequence} after
          * this {@code CompletionStage} has completed.
          *
-         * @implSpec The default implementation of this method behaves as if:
+         * @implSpec The default implementation is equivalent to:
          *
          * 
{@code
          *     webSocket.request(1);
@@ -295,15 +296,15 @@
         /**
          * A binary data has been received.
          *
-         * 

This data located in bytes from the buffer's position to - * its limit. + *

This data is located in bytes from the buffer's position to its + * limit. * *

Return a {@code CompletionStage} which will be used by the * {@code WebSocket} as an indication it may reclaim the * {@code ByteBuffer}. Do not access the {@code ByteBuffer} after * this {@code CompletionStage} has completed. * - * @implSpec The default implementation of this method behaves as if: + * @implSpec The default implementation is equivalent to: * *

{@code
          *     webSocket.request(1);
@@ -340,7 +341,7 @@
          * {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
          * this {@code CompletionStage} has completed.
          *
-         * @implSpec The default implementation of this method behaves as if:
+         * @implSpec The default implementation is equivalent to:
          *
          * 
{@code
          *     webSocket.request(1);
@@ -374,7 +375,7 @@
          * {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
          * this {@code CompletionStage} has completed.
          *
-         * @implSpec The default implementation of this method behaves as if:
+         * @implSpec The default implementation is equivalent to:
          *
          * 
{@code
          *     webSocket.request(1);
@@ -400,11 +401,9 @@
          * Receives a Close message indicating the WebSocket's input has been
          * closed.
          *
-         * 

This is the last invocation from the {@code WebSocket}. By the - * time this invocation begins the WebSocket's input will have - * been closed. Be prepared to receive this invocation at any time after - * {@code onOpen} regardless of whether or not any messages have been - * requested from the {@code WebSocket}. + *

This is the last invocation from the specified {@code WebSocket}. + * By the time this invocation begins the WebSocket's input will have + * been closed. * *

A Close message consists of a status code and a reason for * closing. The status code is an integer from the range @@ -421,8 +420,9 @@ * @apiNote Returning a {@code CompletionStage} that never completes, * effectively disables the reciprocating closure of the output. * - *

To specify a custom closure code and/or reason code the sendClose - * may be invoked from inside onClose call: + *

To specify a custom closure code or reason code the + * {@code sendClose} method may be invoked from inside the + * {@code onClose} invocation: *

{@code
          *  public CompletionStage onClose(WebSocket webSocket,
          *                                    int statusCode,
@@ -475,7 +475,7 @@
     }
 
     /**
-     * Sends a textual data with characters from the given {@code CharSequence}.
+     * Sends a textual data with characters from the given character sequence.
      *
      * 

The character sequence must not be modified until the * {@code CompletableFuture} returned from this method has completed. @@ -500,14 +500,14 @@ * {@code false} otherwise * * @return a {@code CompletableFuture} that completes, with this WebSocket, - * when the message has been sent + * when the data has been sent */ CompletableFuture sendText(CharSequence data, boolean last); /** - * Sends a binary data with bytes from the given {@code ByteBuffer}. + * Sends a binary data with bytes from the given buffer. * - *

The data located in bytes from the buffer's position to its limit. + *

The data is located in 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. @@ -529,12 +529,12 @@ * {@code false} otherwise * * @return a {@code CompletableFuture} that completes, with this WebSocket, - * when the message has been sent + * when the data has been sent */ CompletableFuture sendBinary(ByteBuffer data, boolean last); /** - * Sends a Ping message with bytes from the given {@code ByteBuffer}. + * Sends a Ping message with bytes from the given buffer. * *

The message consists of not more than {@code 125} bytes from the * buffer's position to its limit. Upon normal completion of a @@ -545,7 +545,7 @@ * complete exceptionally with: *

    *
  • {@link IllegalStateException} - - * if the previous Ping or Pong message has not been sent yet + * if there is a pending ping or pong send operation *
  • {@link IllegalArgumentException} - * if the message is too long *
  • {@link IOException} - @@ -561,7 +561,7 @@ CompletableFuture sendPing(ByteBuffer message); /** - * Sends a Pong message with bytes from the given {@code ByteBuffer}. + * Sends a Pong message with bytes from the given buffer. * *

    The message consists of not more than {@code 125} bytes from the * buffer's position to its limit. Upon normal completion of a @@ -572,7 +572,7 @@ * complete exceptionally with: *

      *
    • {@link IllegalStateException} - - * if the previous Ping or Pong message has not been sent yet + * if there is a pending ping or pong send operation *
    • {@link IllegalArgumentException} - * if the message is too long *
    • {@link IOException} - @@ -604,20 +604,21 @@ *
    • {@link IllegalArgumentException} - * if {@code statusCode} is illegal *
    • {@link IOException} - - * if an I/O error occurs, or if the output is closed + * if an I/O error occurs, or if the output is closed, + * or {@code reason} is illegal *
    * *

    Unless the {@code CompletableFuture} returned from this method * completes with {@code IllegalArgumentException}, or the method throws * {@code NullPointerException}, the output will be closed. * - *

    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 + *

    If not already closed, the input remains open until a Close message + * {@linkplain Listener#onClose(WebSocket, int, String) received}, or + * {@code abort} is invoked, or an * {@linkplain Listener#onError(WebSocket, Throwable) error} occurs. * * @apiNote Use the provided integer constant {@link #NORMAL_CLOSURE} as a - * status code and an empty string as a reason in a typical case + * status code and an empty string as a reason in a typical case: *

    {@code
          *     CompletableFuture webSocket = ...
          *     webSocket.thenCompose(ws -> ws.sendText("Hello, ", false))
    @@ -626,6 +627,10 @@
          *              .join();
          * }
    * + * The {@code sendClose} method does not close this WebSocket's input. It + * merely closes this WebSocket's output by sending a Close message. To + * enforce closing input, invoke the {@code abort} method. + * * @param statusCode * the status code * @param reason diff -r 7f921a5a6e10 -r 58e16ad3fb98 src/java.net.http/share/classes/jdk/internal/net/http/websocket/WebSocketImpl.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/WebSocketImpl.java Wed Mar 21 16:30:10 2018 +0000 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/WebSocketImpl.java Wed Mar 21 16:50:25 2018 +0000 @@ -292,7 +292,7 @@ if (!isLegalToSendFromClient(statusCode)) { result = failedFuture(new IllegalArgumentException("statusCode")); } else if (!isLegalReason(reason)) { - result = failedFuture(new IllegalArgumentException("reason")); + result = failedFuture(new IOException("reason")); } else if (!outputClosed.compareAndSet(false, true)){ result = failedFuture(new IOException("Output closed")); } else { diff -r 7f921a5a6e10 -r 58e16ad3fb98 test/jdk/java/net/httpclient/websocket/WebSocketTest.java --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java Wed Mar 21 16:30:10 2018 +0000 +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java Wed Mar 21 16:50:25 2018 +0000 @@ -95,14 +95,14 @@ assertFails(IOE, webSocket.sendText(Support.malformedString(), true)); assertFails(IOE, webSocket.sendText(Support.malformedString(), false)); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(124))); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(125))); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(128))); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(256))); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(257))); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWith2NBytes((123 / 2) + 1))); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.malformedString())); - assertFails(IAE, webSocket.sendClose(NORMAL_CLOSURE, Support.incompleteString())); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(124))); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(125))); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(128))); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(256))); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(257))); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.stringWith2NBytes((123 / 2) + 1))); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.malformedString())); + assertFails(IOE, webSocket.sendClose(NORMAL_CLOSURE, Support.incompleteString())); assertFails(IAE, webSocket.sendClose(-2, "a reason")); assertFails(IAE, webSocket.sendClose(-1, "a reason"));