Path: blob/master/src/java.net.http/share/classes/java/net/http/WebSocket.java
41159 views
/*1* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.net.http;2627import java.io.IOException;28import java.net.URI;29import java.nio.ByteBuffer;30import java.time.Duration;31import java.util.concurrent.CompletableFuture;32import java.util.concurrent.CompletionStage;3334/**35* A WebSocket Client.36*37* <p> {@code WebSocket} instances are created through {@link WebSocket.Builder}.38*39* <p> WebSocket has an input and an output side. These sides are independent40* from each other. A side can either be open or closed. Once closed, the side41* remains closed. WebSocket messages are sent through a {@code WebSocket} and42* received through a {@code WebSocket.Listener} associated with it. Messages43* can be sent until the WebSocket's output is closed, and received until the44* WebSocket's input is closed.45*46* <p> A send method is any of the {@code sendText}, {@code sendBinary},47* {@code sendPing}, {@code sendPong} and {@code sendClose} methods of48* {@code WebSocket}. A send method initiates a send operation and returns a49* {@code CompletableFuture} which completes once the operation has completed.50* If the {@code CompletableFuture} completes normally the operation is51* considered succeeded. If the {@code CompletableFuture} completes52* exceptionally, the operation is considered failed. An operation that has been53* initiated but not yet completed is considered pending.54*55* <p> A receive method is any of the {@code onText}, {@code onBinary},56* {@code onPing}, {@code onPong} and {@code onClose} methods of57* {@code Listener}. WebSocket initiates a receive operation by invoking a58* receive method on the listener. The listener then must return a59* {@code CompletionStage} which completes once the operation has completed.60*61* <p> To control receiving of messages, a WebSocket maintains an62* <a id="counter">internal counter</a>. This counter's value is a number of63* times the WebSocket has yet to invoke a receive method. While this counter is64* zero the WebSocket does not invoke receive methods. The counter is65* incremented by {@code n} when {@code request(n)} is called. The counter is66* decremented by one when the WebSocket invokes a receive method.67* {@code onOpen} and {@code onError} are not receive methods. WebSocket invokes68* {@code onOpen} prior to any other methods on the listener. WebSocket invokes69* {@code onOpen} at most once. WebSocket may invoke {@code onError} at any70* given time. If the WebSocket invokes {@code onError} or {@code onClose}, then71* no further listener's methods will be invoked, no matter the value of the72* counter. For a newly built WebSocket the counter is zero.73*74* <p> Unless otherwise stated, {@code null} arguments will cause methods75* of {@code WebSocket} to throw {@code NullPointerException}, similarly,76* {@code WebSocket} will not pass {@code null} arguments to methods of77* {@code Listener}. The state of a WebSocket is not changed by the invocations78* that throw or return a {@code CompletableFuture} that completes with one of79* the {@code NullPointerException}, {@code IllegalArgumentException},80* {@code IllegalStateException} exceptions.81*82* <p> {@code WebSocket} handles received Ping and Close messages automatically83* (as per the WebSocket Protocol) by replying with Pong and Close messages. If84* the listener receives Ping or Close messages, no mandatory actions from the85* listener are required.86*87* @apiNote The relationship between a WebSocket and the associated Listener is88* analogous to that of a Subscription and the associated Subscriber of type89* {@link java.util.concurrent.Flow}.90*91* @since 1192*/93public interface WebSocket {9495/**96* The WebSocket Close message status code (<code>{@value}</code>),97* indicating normal closure, meaning that the purpose for which the98* connection was established has been fulfilled.99*100* @see #sendClose(int, String)101* @see Listener#onClose(WebSocket, int, String)102*/103int NORMAL_CLOSURE = 1000;104105/**106* A builder of {@linkplain WebSocket WebSocket Clients}.107*108* <p> Builders are created by invoking109* {@link HttpClient#newWebSocketBuilder HttpClient.newWebSocketBuilder}.110* The intermediate (setter-like) methods change the state of the builder111* and return the same builder they have been invoked on. If an intermediate112* method is not invoked, an appropriate default value (or behavior) will be113* assumed. A {@code Builder} is not safe for use by multiple threads114* without external synchronization.115*116* @since 11117*/118interface Builder {119120/**121* Adds the given name-value pair to the list of additional HTTP headers122* sent during the opening handshake.123*124* <p> Headers defined in the125* <a href="https://tools.ietf.org/html/rfc6455#section-11.3">WebSocket126* Protocol</a> are illegal. If this method is not invoked, no127* additional HTTP headers will be sent.128*129* @param name130* the header name131* @param value132* the header value133*134* @return this builder135*/136Builder header(String name, String value);137138/**139* Sets a timeout for establishing a WebSocket connection.140*141* <p> If the connection is not established within the specified142* duration then building of the {@code WebSocket} will fail with143* {@link HttpTimeoutException}. If this method is not invoked then the144* infinite timeout is assumed.145*146* @param timeout147* the timeout, non-{@linkplain Duration#isNegative() negative},148* non-{@linkplain Duration#ZERO ZERO}149*150* @return this builder151*/152Builder connectTimeout(Duration timeout);153154/**155* Sets a request for the given subprotocols.156*157* <p> After the {@code WebSocket} has been built, the actual158* subprotocol can be queried through159* {@link WebSocket#getSubprotocol WebSocket.getSubprotocol()}.160*161* <p> Subprotocols are specified in the order of preference. The most162* preferred subprotocol is specified first. If there are any additional163* subprotocols they are enumerated from the most preferred to the least164* preferred.165*166* <p> Subprotocols not conforming to the syntax of subprotocol167* identifiers are illegal. If this method is not invoked then no168* subprotocols will be requested.169*170* @param mostPreferred171* the most preferred subprotocol172* @param lesserPreferred173* the lesser preferred subprotocols174*175* @return this builder176*/177Builder subprotocols(String mostPreferred, String... lesserPreferred);178179/**180* Builds a {@link WebSocket} connected to the given {@code URI} and181* associated with the given {@code Listener}.182*183* <p> Returns a {@code CompletableFuture} which will either complete184* normally with the resulting {@code WebSocket} or complete185* exceptionally with one of the following errors:186* <ul>187* <li> {@link IOException} -188* if an I/O error occurs189* <li> {@link WebSocketHandshakeException} -190* if the opening handshake fails191* <li> {@link HttpTimeoutException} -192* if the opening handshake does not complete within193* the timeout194* <li> {@link InterruptedException} -195* if the operation is interrupted196* <li> {@link SecurityException} -197* if a security manager has been installed and it denies198* {@link java.net.URLPermission access} to {@code uri}.199* <a href="HttpClient.html#securitychecks">Security checks</a>200* contains more information relating to the security context201* in which the listener is invoked.202* <li> {@link IllegalArgumentException} -203* if any of the arguments of this builder's methods are204* illegal205* </ul>206*207* @param uri208* the WebSocket URI209* @param listener210* the listener211*212* @return a {@code CompletableFuture} with the {@code WebSocket}213*/214CompletableFuture<WebSocket> buildAsync(URI uri, Listener listener);215}216217/**218* The receiving interface of {@code WebSocket}.219*220* <p> A {@code WebSocket} invokes methods of the associated listener221* passing itself as an argument. These methods are invoked in a thread-safe222* manner, such that the next invocation may start only after the previous223* one has finished.224*225* <p> When data has been received, the {@code WebSocket} invokes a receive226* method. Methods {@code onText}, {@code onBinary}, {@code onPing} and227* {@code onPong} must return a {@code CompletionStage} that completes once228* the message has been received by the listener. If a listener's method229* returns {@code null} rather than a {@code CompletionStage},230* {@code WebSocket} will behave as if the listener returned a231* {@code CompletionStage} that is already completed normally.232*233* <p> An {@code IOException} raised in {@code WebSocket} will result in an234* invocation of {@code onError} with that exception (if the input is not235* closed). Unless otherwise stated if the listener's method throws an236* exception or a {@code CompletionStage} returned from a method completes237* exceptionally, the WebSocket will invoke {@code onError} with this238* exception.239*240* @apiNote The strict sequential order of invocations from241* {@code WebSocket} to {@code Listener} means, in particular, that the242* {@code Listener}'s methods are treated as non-reentrant. This means that243* {@code Listener} implementations do not need to be concerned with244* possible recursion or the order in which they invoke245* {@code WebSocket.request} in relation to their processing logic.246*247* <p> Careful attention may be required if a listener is associated248* with more than a single {@code WebSocket}. In this case invocations249* related to different instances of {@code WebSocket} may not be ordered250* and may even happen concurrently.251*252* <p> {@code CompletionStage}s returned from the receive methods have253* nothing to do with the254* <a href="WebSocket.html#counter">counter of invocations</a>.255* Namely, a {@code CompletionStage} does not have to be completed in order256* to receive more invocations of the listener's methods.257* Here is an example of a listener that requests invocations, one at a258* time, until a complete message has been accumulated, then processes259* the result, and completes the {@code CompletionStage}:260* <pre>{@code WebSocket.Listener listener = new WebSocket.Listener() {261*262* List<CharSequence> parts = new ArrayList<>();263* CompletableFuture<?> accumulatedMessage = new CompletableFuture<>();264*265* public CompletionStage<?> onText(WebSocket webSocket,266* CharSequence message,267* boolean last) {268* parts.add(message);269* webSocket.request(1);270* if (last) {271* processWholeText(parts);272* parts = new ArrayList<>();273* accumulatedMessage.complete(null);274* CompletionStage<?> cf = accumulatedMessage;275* accumulatedMessage = new CompletableFuture<>();276* return cf;277* }278* return accumulatedMessage;279* }280* ...281* } } </pre>282*283* @since 11284*/285interface Listener {286287/**288* A {@code WebSocket} has been connected.289*290* <p> This is the initial invocation and it is made once. It is291* typically used to make a request for more invocations.292*293* @implSpec The default implementation is equivalent to:294* <pre>{@code webSocket.request(1); }</pre>295*296* @param webSocket297* the WebSocket that has been connected298*/299default void onOpen(WebSocket webSocket) { webSocket.request(1); }300301/**302* A textual data has been received.303*304* <p> Return a {@code CompletionStage} which will be used by the305* {@code WebSocket} as an indication it may reclaim the306* {@code CharSequence}. Do not access the {@code CharSequence} after307* this {@code CompletionStage} has completed.308*309* @implSpec The default implementation is equivalent to:310* <pre>{@code webSocket.request(1);311* return null; }</pre>312*313* @implNote The {@code data} is always a legal UTF-16 sequence.314*315* @param webSocket316* the WebSocket on which the data has been received317* @param data318* the data319* @param last320* whether this invocation completes the message321*322* @return a {@code CompletionStage} which completes when the323* {@code CharSequence} may be reclaimed; or {@code null} if it may be324* reclaimed immediately325*/326default CompletionStage<?> onText(WebSocket webSocket,327CharSequence data,328boolean last) {329webSocket.request(1);330return null;331}332333/**334* A binary data has been received.335*336* <p> This data is located in bytes from the buffer's position to its337* limit.338*339* <p> Return a {@code CompletionStage} which will be used by the340* {@code WebSocket} as an indication it may reclaim the341* {@code ByteBuffer}. Do not access the {@code ByteBuffer} after342* this {@code CompletionStage} has completed.343*344* @implSpec The default implementation is equivalent to:345* <pre>{@code webSocket.request(1);346* return null; }</pre>347*348* @param webSocket349* the WebSocket on which the data has been received350* @param data351* the data352* @param last353* whether this invocation completes the message354*355* @return a {@code CompletionStage} which completes when the356* {@code ByteBuffer} may be reclaimed; or {@code null} if it may be357* reclaimed immediately358*/359default CompletionStage<?> onBinary(WebSocket webSocket,360ByteBuffer data,361boolean last) {362webSocket.request(1);363return null;364}365366/**367* A Ping message has been received.368*369* <p> As guaranteed by the WebSocket Protocol, the message consists of370* not more than {@code 125} bytes. These bytes are located from the371* buffer's position to its limit.372*373* <p> Given that the WebSocket implementation will automatically send a374* reciprocal pong when a ping is received, it is rarely required to375* send a pong message explicitly when a ping is received.376*377* <p> Return a {@code CompletionStage} which will be used by the378* {@code WebSocket} as a signal it may reclaim the379* {@code ByteBuffer}. Do not access the {@code ByteBuffer} after380* this {@code CompletionStage} has completed.381*382* @implSpec The default implementation is equivalent to:383* <pre>{@code webSocket.request(1);384* return null; }</pre>385*386* @param webSocket387* the WebSocket on which the message has been received388* @param message389* the message390*391* @return a {@code CompletionStage} which completes when the392* {@code ByteBuffer} may be reclaimed; or {@code null} if it may be393* reclaimed immediately394*/395default CompletionStage<?> onPing(WebSocket webSocket,396ByteBuffer message) {397webSocket.request(1);398return null;399}400401/**402* A Pong message has been received.403*404* <p> As guaranteed by the WebSocket Protocol, the message consists of405* not more than {@code 125} bytes. These bytes are located from the406* buffer's position to its limit.407*408* <p> Return a {@code CompletionStage} which will be used by the409* {@code WebSocket} as a signal it may reclaim the410* {@code ByteBuffer}. Do not access the {@code ByteBuffer} after411* this {@code CompletionStage} has completed.412*413* @implSpec The default implementation is equivalent to:414* <pre>{@code webSocket.request(1);415* return null; }</pre>416*417* @param webSocket418* the WebSocket on which the message has been received419* @param message420* the message421*422* @return a {@code CompletionStage} which completes when the423* {@code ByteBuffer} may be reclaimed; or {@code null} if it may be424* reclaimed immediately425*/426default CompletionStage<?> onPong(WebSocket webSocket,427ByteBuffer message) {428webSocket.request(1);429return null;430}431432/**433* Receives a Close message indicating the WebSocket's input has been434* closed.435*436* <p> This is the last invocation from the specified {@code WebSocket}.437* By the time this invocation begins the WebSocket's input will have438* been closed.439*440* <p> A Close message consists of a status code and a reason for441* closing. The status code is an integer from the range442* {@code 1000 <= code <= 65535}. The {@code reason} is a string which443* has a UTF-8 representation not longer than {@code 123} bytes.444*445* <p> If the WebSocket's output is not already closed, the446* {@code CompletionStage} returned by this method will be used as an447* indication that the WebSocket's output may be closed. The WebSocket448* will close its output at the earliest of completion of the returned449* {@code CompletionStage} or invoking either of the {@code sendClose}450* or {@code abort} methods.451*452* @apiNote Returning a {@code CompletionStage} that never completes,453* effectively disables the reciprocating closure of the output.454*455* <p> To specify a custom closure code or reason code the456* {@code sendClose} method may be invoked from inside the457* {@code onClose} invocation:458* <pre>{@code public CompletionStage<?> onClose(WebSocket webSocket,459* int statusCode,460* String reason) {461* webSocket.sendClose(CUSTOM_STATUS_CODE, CUSTOM_REASON);462* return new CompletableFuture<Void>();463* } } </pre>464*465* @implSpec The default implementation of this method returns466* {@code null}, indicating that the output should be closed467* immediately.468*469* @param webSocket470* the WebSocket on which the message has been received471* @param statusCode472* the status code473* @param reason474* the reason475*476* @return a {@code CompletionStage} which completes when the477* {@code WebSocket} may be closed; or {@code null} if it may be478* closed immediately479*/480default CompletionStage<?> onClose(WebSocket webSocket,481int statusCode,482String reason) {483return null;484}485486/**487* An error has occurred.488*489* <p> This is the last invocation from the specified WebSocket. By the490* time this invocation begins both the WebSocket's input and output491* will have been closed. A WebSocket may invoke this method on the492* associated listener at any time after it has invoked {@code onOpen},493* regardless of whether or not any invocations have been requested from494* the WebSocket.495*496* <p> If an exception is thrown from this method, resulting behavior is497* undefined.498*499* @param webSocket500* the WebSocket on which the error has occurred501* @param error502* the error503*/504default void onError(WebSocket webSocket, Throwable error) { }505}506507/**508* Sends textual data with characters from the given character sequence.509*510* <p> The character sequence must not be modified until the511* {@code CompletableFuture} returned from this method has completed.512*513* <p> A {@code CompletableFuture} returned from this method can514* complete exceptionally with:515* <ul>516* <li> {@link IllegalStateException} -517* if there is a pending text or binary send operation518* or if the previous binary data does not complete the message519* <li> {@link IOException} -520* if an I/O error occurs, or if the output is closed521* </ul>522*523* @implNote If {@code data} is a malformed UTF-16 sequence, the operation524* will fail with {@code IOException}.525*526* @param data527* the data528* @param last529* {@code true} if this invocation completes the message,530* {@code false} otherwise531*532* @return a {@code CompletableFuture} that completes, with this WebSocket,533* when the data has been sent534*/535CompletableFuture<WebSocket> sendText(CharSequence data, boolean last);536537/**538* Sends binary data with bytes from the given buffer.539*540* <p> The data is located in bytes from the buffer's position to its limit.541* Upon normal completion of a {@code CompletableFuture} returned from this542* method the buffer will have no remaining bytes. The buffer must not be543* accessed until after that.544*545* <p> The {@code CompletableFuture} returned from this method can546* complete exceptionally with:547* <ul>548* <li> {@link IllegalStateException} -549* if there is a pending text or binary send operation550* or if the previous textual data does not complete the message551* <li> {@link IOException} -552* if an I/O error occurs, or if the output is closed553* </ul>554*555* @param data556* the data557* @param last558* {@code true} if this invocation completes the message,559* {@code false} otherwise560*561* @return a {@code CompletableFuture} that completes, with this WebSocket,562* when the data has been sent563*/564CompletableFuture<WebSocket> sendBinary(ByteBuffer data, boolean last);565566/**567* Sends a Ping message with bytes from the given buffer.568*569* <p> The message consists of not more than {@code 125} bytes from the570* buffer's position to its limit. Upon normal completion of a571* {@code CompletableFuture} returned from this method the buffer will572* have no remaining bytes. The buffer must not be accessed until after that.573*574* <p> The {@code CompletableFuture} returned from this method can575* complete exceptionally with:576* <ul>577* <li> {@link IllegalStateException} -578* if there is a pending ping or pong send operation579* <li> {@link IllegalArgumentException} -580* if the message is too long581* <li> {@link IOException} -582* if an I/O error occurs, or if the output is closed583* </ul>584*585* @param message586* the message587*588* @return a {@code CompletableFuture} that completes, with this WebSocket,589* when the Ping message has been sent590*/591CompletableFuture<WebSocket> sendPing(ByteBuffer message);592593/**594* Sends a Pong message with bytes from the given buffer.595*596* <p> The message consists of not more than {@code 125} bytes from the597* buffer's position to its limit. Upon normal completion of a598* {@code CompletableFuture} returned from this method the buffer will have599* no remaining bytes. The buffer must not be accessed until after that.600*601* <p> Given that the WebSocket implementation will automatically send a602* reciprocal pong when a ping is received, it is rarely required to send a603* pong message explicitly.604*605* <p> The {@code CompletableFuture} returned from this method can606* complete exceptionally with:607* <ul>608* <li> {@link IllegalStateException} -609* if there is a pending ping or pong send operation610* <li> {@link IllegalArgumentException} -611* if the message is too long612* <li> {@link IOException} -613* if an I/O error occurs, or if the output is closed614* </ul>615*616* @param message617* the message618*619* @return a {@code CompletableFuture} that completes, with this WebSocket,620* when the Pong message has been sent621*/622CompletableFuture<WebSocket> sendPong(ByteBuffer message);623624/**625* Initiates an orderly closure of this WebSocket's output by626* sending a Close message with the given status code and the reason.627*628* <p> The {@code statusCode} is an integer from the range629* {@code 1000 <= code <= 4999}. Status codes {@code 1002}, {@code 1003},630* {@code 1006}, {@code 1007}, {@code 1009}, {@code 1010}, {@code 1012},631* {@code 1013} and {@code 1015} are illegal. Behaviour in respect to other632* status codes is implementation-specific. A legal {@code reason} is a633* string that has a UTF-8 representation not longer than {@code 123} bytes.634*635* <p> A {@code CompletableFuture} returned from this method can636* complete exceptionally with:637* <ul>638* <li> {@link IllegalArgumentException} -639* if {@code statusCode} is illegal, or640* if {@code reason} is illegal641* <li> {@link IOException} -642* if an I/O error occurs, or if the output is closed643* </ul>644*645* <p> Unless the {@code CompletableFuture} returned from this method646* completes with {@code IllegalArgumentException}, or the method throws647* {@code NullPointerException}, the output will be closed.648*649* <p> If not already closed, the input remains open until a Close message650* {@linkplain Listener#onClose(WebSocket, int, String) received}, or651* {@code abort} is invoked, or an652* {@linkplain Listener#onError(WebSocket, Throwable) error} occurs.653*654* @apiNote Use the provided integer constant {@link #NORMAL_CLOSURE} as a655* status code and an empty string as a reason in a typical case:656* <pre>{@code CompletableFuture<WebSocket> webSocket = ...657* webSocket.thenCompose(ws -> ws.sendText("Hello, ", false))658* .thenCompose(ws -> ws.sendText("world!", true))659* .thenCompose(ws -> ws.sendClose(WebSocket.NORMAL_CLOSURE, ""))660* .join(); }</pre>661*662* The {@code sendClose} method does not close this WebSocket's input. It663* merely closes this WebSocket's output by sending a Close message. To664* enforce closing the input, invoke the {@code abort} method. Here is an665* example of an application that sends a Close message, and then starts a666* timer. Once no data has been received within the specified timeout, the667* timer goes off and the alarm aborts {@code WebSocket}:668* <pre>{@code MyAlarm alarm = new MyAlarm(webSocket::abort);669* WebSocket.Listener listener = new WebSocket.Listener() {670*671* public CompletionStage<?> onText(WebSocket webSocket,672* CharSequence data,673* boolean last) {674* alarm.snooze();675* ...676* }677* ...678* };679* ...680* Runnable startTimer = () -> {681* MyTimer idleTimer = new MyTimer();682* idleTimer.add(alarm, 30, TimeUnit.SECONDS);683* };684* webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok").thenRun(startTimer);685* } </pre>686*687* @param statusCode688* the status code689* @param reason690* the reason691*692* @return a {@code CompletableFuture} that completes, with this WebSocket,693* when the Close message has been sent694*/695CompletableFuture<WebSocket> sendClose(int statusCode, String reason);696697/**698* Increments the counter of invocations of receive methods.699*700* <p> This WebSocket will invoke {@code onText}, {@code onBinary},701* {@code onPing}, {@code onPong} or {@code onClose} methods on the702* associated listener (i.e. receive methods) up to {@code n} more times.703*704* @apiNote The parameter of this method is the number of invocations being705* requested from this WebSocket to the associated listener, not the number706* of messages. Sometimes a message may be delivered to the listener in a707* single invocation, but not always. For example, Ping, Pong and Close708* messages are delivered in a single invocation of {@code onPing},709* {@code onPong} and {@code onClose} methods respectively. However, whether710* or not Text and Binary messages are delivered in a single invocation of711* {@code onText} and {@code onBinary} methods depends on the boolean712* argument ({@code last}) of these methods. If {@code last} is713* {@code false}, then there is more to a message than has been delivered to714* the invocation.715*716* <p> Here is an example of a listener that requests invocations, one at a717* time, until a complete message has been accumulated, and then processes718* the result:719* <pre>{@code WebSocket.Listener listener = new WebSocket.Listener() {720*721* StringBuilder text = new StringBuilder();722*723* public CompletionStage<?> onText(WebSocket webSocket,724* CharSequence message,725* boolean last) {726* text.append(message);727* if (last) {728* processCompleteTextMessage(text);729* text = new StringBuilder();730* }731* webSocket.request(1);732* return null;733* }734* ...735* } } </pre>736*737* @param n738* the number of invocations739*740* @throws IllegalArgumentException741* if {@code n <= 0}742*/743void request(long n);744745/**746* Returns the subprotocol used by this WebSocket.747*748* @return the subprotocol, or an empty string if there's no subprotocol749*/750String getSubprotocol();751752/**753* Tells whether this WebSocket's output is closed.754*755* <p> If this method returns {@code true}, subsequent invocations will also756* return {@code true}.757*758* @return {@code true} if closed, {@code false} otherwise759*/760boolean isOutputClosed();761762/**763* Tells whether this WebSocket's input is closed.764*765* <p> If this method returns {@code true}, subsequent invocations will also766* return {@code true}.767*768* @return {@code true} if closed, {@code false} otherwise769*/770boolean isInputClosed();771772/**773* Closes this WebSocket's input and output abruptly.774*775* <p> When this method returns both the input and the output will have been776* closed. Any pending send operations will fail with {@code IOException}.777* Subsequent invocations of {@code abort} will have no effect.778*/779void abort();780}781782783