http-client-branch: (WebSocket) API wording for back-pressure http-client-branch
authorprappo
Wed, 21 Mar 2018 11:39:30 +0000
branchhttp-client-branch
changeset 56328 161f716753d7
parent 56327 efd50952acd9
child 56329 254f6c8277f9
http-client-branch: (WebSocket) API wording for back-pressure
src/java.net.http/share/classes/java/net/http/WebSocket.java
test/jdk/java/net/httpclient/examples/WebSocketExample.java
--- a/src/java.net.http/share/classes/java/net/http/WebSocket.java	Wed Mar 21 10:25:26 2018 +0000
+++ b/src/java.net.http/share/classes/java/net/http/WebSocket.java	Wed Mar 21 11:39:30 2018 +0000
@@ -40,7 +40,7 @@
  * {@code abort} methods.
  *
  * <p> WebSocket messages are sent through a {@code WebSocket} and received
- * through the {@code WebSocket}'s {@code Listener}. Messages can be sent until
+ * through the {@code WebSocket.Listener}. Messages can be sent until
  * the output is closed, and received until the input is closed.
  * A {@code WebSocket} whose output and input are both closed may be considered
  * itself closed. To check these states use {@link #isOutputClosed()} and
@@ -50,12 +50,19 @@
  * completes normally if the message is sent or completes exceptionally if an
  * error occurs.
  *
- * <p> To receive a message, first request it. If {@code n} messages are
- * requested, the listener will receive up to {@code n} more invocations of the
- * designated methods from the {@code WebSocket}. To request messages use
- * {@link #request(long)}. Request is an additive operation, that is
- * {@code request(n)} followed by {@code request(m)} is equivalent to
- * {@code request(n + m)}.
+ * A <i>receive method</i> is any of the {@code onText}, {@code onBinary},
+ * {@code onPing}, {@code onPong} and {@code onClose} methods of
+ * {@code Listener}. A {@code WebSocket} maintains an internal counter.
+ * This counter indicates how many invocations of the associated listener's
+ * receive methods have been requested, but not yet made. While this counter is
+ * zero the {@code WebSocket} does not invoke any of the receive methods. The
+ * counter is incremented by {@code n} when {@code request(n)} is called. The
+ * counter is decremented by one when the {@code WebSocket} invokes a receive
+ * method. {@code onError} is not a receive method. The {@code WebSocket} may
+ * invoke {@code onError} at any given time. If the {@code WebSocket} invokes
+ * {@code onError} or {@code onClose}, then no further listener methods will be
+ * invoked, no matter the value of the counter. For a newly built
+ * {@code WebSocket} the value of the counter is zero.
  *
  * <p> When sending or receiving a message in parts, a whole message is
  * transferred as a sequence of one or more invocations where the last
@@ -79,6 +86,10 @@
  * listener receives Ping or Close messages, no mandatory actions from the
  * listener are required.
  *
+ * @apiNote The relationship between a WebSocket and an instance of Listener
+ * associated with it is analogous to that of Subscription and the related
+ * Subscriber of type {@link java.util.concurrent.Flow}.
+ *
  * @since 11
  */
 public interface WebSocket {
@@ -635,14 +646,48 @@
     CompletableFuture<WebSocket> sendClose(int statusCode, String reason);
 
     /**
-     * Requests {@code n} more messages from this {@code WebSocket}.
+     * Increments the counter of invocations requested from this
+     * {@code WebSocket} to the associated listener by the given number.
+     *
+     * <p> This WebSocket will invoke {@code onText}, {@code onBinary},
+     * {@code onPing}, {@code onPong} or {@code onClose} methods on the
+     * associated listener up to {@code n} more times.
+     *
+     * @apiNote The parameter of this method is the number of invocations being
+     * requested from this {@code WebSocket} to the associated {@code Listener},
+     * not the number of messages. Sometimes a message may be delivered in a
+     * single invocation, but not always. For example, Ping, Pong and Close
+     * messages are delivered in a single invocation of {@code onPing},
+     * {@code onPong} and {@code onClose} respectively. However, whether or not
+     * Text and Binary messages are delivered in a single invocation of
+     * {@code onText} and {@code onBinary} depends on the boolean argument
+     * ({@code last}) of these methods. If {@code last} is {@code false}, then
+     * there is more to a message than has been delivered to the invocation.
      *
-     * <p> This {@code WebSocket} will invoke its listener's {@code onText},
-     * {@code onBinary}, {@code onPing}, {@code onPong} or {@code onClose}
-     * methods up to {@code n} more times.
+     * <p> Here is an example of a listener that requests invocations, one at a
+     * time, until a complete message has been accumulated, then processes the
+     * result:
+     * <pre>WebSocket.Listener listener = new WebSocket.Listener() {
+     *
+     *    StringBuilder text = new StringBuilder();
+     *
+     *    &#64;Override
+     *    public CompletionStage&lt;?&gt; onText(WebSocket webSocket,
+     *                                           CharSequence message,
+     *                                           boolean last) {
+     *        text.append(message);
+     *        if (last) {
+     *            processCompleteTextMessage(text);
+     *            text = new StringBuilder();
+     *        }
+     *        webSocket.request(1);
+     *        return null;
+     *    }
+     *    ...
+     * }</pre>
      *
      * @param n
-     *         the number of messages requested
+     *         the number of invocations
      *
      * @throws IllegalArgumentException
      *         if {@code n <= 0}
--- a/test/jdk/java/net/httpclient/examples/WebSocketExample.java	Wed Mar 21 10:25:26 2018 +0000
+++ b/test/jdk/java/net/httpclient/examples/WebSocketExample.java	Wed Mar 21 11:39:30 2018 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 
 import java.net.http.HttpClient;
 import java.net.http.WebSocket;
+import java.util.concurrent.CompletionStage;
 
 /*
  * THE CONTENTS OF THIS FILE HAVE TO BE IN SYNC WITH THE EXAMPLES USED IN THE
@@ -56,4 +57,26 @@
         CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
                 .buildAsync(URI.create("ws://websocket.example.com"), listener);
     }
+
+    public void requestExample() {
+        WebSocket.Listener listener = new WebSocket.Listener() {
+
+            StringBuilder text = new StringBuilder();
+
+            @Override
+            public CompletionStage<?> onText(WebSocket webSocket,
+                                             CharSequence message,
+                                             boolean last) {
+                text.append(message);
+                if (last) {
+                    processCompleteTextMessage(text);
+                    text = new StringBuilder();
+                }
+                webSocket.request(1);
+                return null;
+            }
+        };
+    }
+
+    static void processCompleteTextMessage(CharSequence result) { }
 }