# HG changeset patch # User prappo # Date 1521632370 0 # Node ID 161f716753d7545e54f59262211570fb8c149e94 # Parent efd50952acd99447b46ec75ae891be226ec2cbe8 http-client-branch: (WebSocket) API wording for back-pressure diff -r efd50952acd9 -r 161f716753d7 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 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. * *

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

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 receive method 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. * *

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

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

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

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

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;
+     *    }
+     *    ...
+     * }
* * @param n - * the number of messages requested + * the number of invocations * * @throws IllegalArgumentException * if {@code n <= 0} diff -r efd50952acd9 -r 161f716753d7 test/jdk/java/net/httpclient/examples/WebSocketExample.java --- 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 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) { } }