< prev index next >
src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/WebSocket.java
Print this page
*** 24,85 ****
*/
package jdk.incubator.http;
import java.io.IOException;
- import java.net.ProtocolException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
/**
! * A WebSocket client conforming to RFC 6455.
* {@Incubating}
*
! * <p> A {@code WebSocket} provides full-duplex communication over a TCP
! * connection.
*
! * <p> To create a {@code WebSocket} use a {@linkplain HttpClient#newWebSocketBuilder(
! * URI, Listener) builder}. Once a {@code WebSocket} is built, it's ready
! * to send and receive messages. When the {@code WebSocket} is no longer needed
! * it must be closed: a Close message must both be {@linkplain #sendClose
! * sent} and {@linkplain Listener#onClose(WebSocket, int, String) received}.
! * The {@code WebSocket} may be also closed {@linkplain #abort() abruptly}.
! *
! * <p> Once closed the {@code WebSocket} remains {@linkplain #isClosed() closed}
! * and cannot be reopened.
! *
! * <p> Messages of type {@code X} (where {@code X} is one of: Text, Binary,
! * Ping, Pong or Close) are sent and received asynchronously through the {@code
! * WebSocket.send{X}} and {@link WebSocket.Listener}{@code .on{X}} methods
! * respectively. Each method returns a {@link CompletionStage} which completes
! * when the operation has completed.
! *
! * <p> Note that messages (of any type) are received only if {@linkplain
! * #request(long) requested}.
! *
! * <p> One outstanding send operation is permitted. No further send operation
! * can be initiated before the previous one has completed. When sending, a
! * message must not be modified until the returned {@link CompletableFuture}
! * completes (either normally or exceptionally).
! *
! * <p> Text and Binary messages can be sent and received as a whole or in parts.
! * A whole message is transferred as a sequence of one or more invocations of a
! * corresponding method where the last invocation is identified via an
! * additional method argument.
! *
! * <p> If the message is contained in a {@link ByteBuffer}, bytes are considered
! * arranged from the {@code buffer}'s {@link ByteBuffer#position() position} to
! * the {@code buffer}'s {@link ByteBuffer#limit() limit}.
! *
! * <p> Unless otherwise stated, {@code null} parameter values will cause methods
! * and constructors to throw {@link NullPointerException}.
*
! * @implNote This implementation's methods do not block before returning
! * a {@code CompletableFuture}.
*
* @since 9
*/
public interface WebSocket {
--- 24,88 ----
*/
package jdk.incubator.http;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
/**
! * A WebSocket client.
* {@Incubating}
*
! * <p> To create a {@code WebSocket} use the {@link HttpClient#newWebSocketBuilder}
! * method. To close a {@code WebSocket} use one of the {@code sendClose} or
! * {@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
! * 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
! * {@link #isInputClosed()}.
*
! * <p> Methods that send messages return {@code CompletableFuture} which
! * 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)}.
! *
! * <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
! * invocation is identified via an additional method argument.
! *
! * <p> Unless otherwise stated, {@code null} arguments will cause methods
! * of {@code WebSocket} to throw {@code NullPointerException}, similarly,
! * {@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> A {@code WebSocket} invokes methods of its listener in a thread-safe
! * manner.
! *
! * <p> {@code WebSocket} handles Ping and Close messages automatically (as per
! * RFC 6455) by replying with Pong and Close messages respectively. If the
! * listener receives Ping or Close messages, no mandatory actions from the
! * listener are required.
*
* @since 9
*/
public interface WebSocket {
*** 95,127 ****
/**
* A builder for creating {@code WebSocket} instances.
* {@Incubating}
*
! * <p> To build a {@code WebSocket}, {@linkplain HttpClient#newWebSocketBuilder(
! * URI, Listener) create} a builder, configure it as required by
* calling intermediate methods (the ones that return the builder itself),
! * then finally call {@link #buildAsync()} to get a {@link
! * CompletableFuture} with resulting {@code WebSocket}.
*
! * <p> If an intermediate method has not been called, an appropriate
! * default value (or behavior) will be used. Unless otherwise noted, a
! * repeated call to an intermediate method overwrites the previous value (or
! * overrides the previous behaviour).
! *
! * <p> Instances of {@code Builder} are not safe for use by multiple threads
! * without external synchronization.
*
* @since 9
*/
interface Builder {
/**
! * Adds the given name-value pair to the list of additional headers for
! * the opening handshake.
*
! * <p> Headers defined in WebSocket Protocol are not allowed to be added.
*
* @param name
* the header name
* @param value
* the header value
--- 98,125 ----
/**
* A builder for creating {@code WebSocket} instances.
* {@Incubating}
*
! * <p> To obtain a {@code WebSocket} configure a builder as required by
* calling intermediate methods (the ones that return the builder itself),
! * then call {@code buildAsync()}. If an intermediate method is not called,
! * an appropriate default value (or behavior) will be assumed.
*
! * <p> Unless otherwise stated, {@code null} arguments will cause methods of
! * {@code Builder} to throw {@code NullPointerException}.
*
* @since 9
*/
interface Builder {
/**
! * Adds the given name-value pair to the list of additional HTTP headers
! * sent during the opening handshake.
*
! * <p> Headers defined in WebSocket Protocol are illegal. If this method
! * is not invoked, no additional HTTP headers will be sent.
*
* @param name
* the header name
* @param value
* the header value
*** 129,590 ****
* @return this builder
*/
Builder header(String name, String value);
/**
! * Includes a request for the given subprotocols during the opening
! * handshake.
! *
! * <p> Among the requested subprotocols at most one will be chosen by
! * the server. This subprotocol will be available from {@link
! * WebSocket#getSubprotocol}. Subprotocols are specified in the order of
! * preference.
*
! * <p> Each of the given subprotocols must conform to the relevant
! * rules defined in the WebSocket Protocol.
*
! * <p> If this method is not invoked then no subprotocols are requested.
! *
! * @param mostPreferred
! * the most preferred subprotocol
! * @param lesserPreferred
! * the lesser preferred subprotocols, with the least preferred
! * at the end
*
* @return this builder
*/
! Builder subprotocols(String mostPreferred, String... lesserPreferred);
/**
! * Sets a timeout for the opening handshake.
! *
! * <p> If the opening handshake does not complete within the specified
! * duration then the {@code CompletableFuture} returned from {@link
! * #buildAsync()} completes exceptionally with a {@link
! * HttpTimeoutException}.
*
! * <p> If this method is not invoked then the timeout is deemed infinite.
*
! * @param timeout
! * the timeout, non-{@linkplain Duration#isNegative() negative},
! * non-{@linkplain Duration#ZERO ZERO}
*
* @return this builder
*/
! Builder connectTimeout(Duration timeout);
/**
! * Builds a {@code WebSocket}.
*
! * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
! * normally with the {@code WebSocket} when it is connected or completes
! * exceptionally if an error occurs.
! *
! * <p> {@code CompletableFuture} may complete exceptionally with the
! * following errors:
* <ul>
* <li> {@link IOException} -
* if an I/O error occurs
* <li> {@link WebSocketHandshakeException} -
* if the opening handshake fails
* <li> {@link HttpTimeoutException} -
* if the opening handshake does not complete within
! * the specified {@linkplain #connectTimeout(Duration) duration}
* <li> {@link InterruptedException} -
! * if the operation was interrupted
* <li> {@link SecurityException} -
! * if a security manager is set, and the caller does not
! * have a {@link java.net.URLPermission} for the WebSocket URI
* <li> {@link IllegalArgumentException} -
! * if any of the additional {@link #header(String, String)
! * headers} are illegal;
! * or if any of the WebSocket Protocol rules relevant to {@link
! * #subprotocols(String, String...) subprotocols} are violated;
! * or if the {@link #connectTimeout(Duration) connect timeout}
! * is invalid;
* </ul>
*
* @return a {@code CompletableFuture} with the {@code WebSocket}
*/
! CompletableFuture<WebSocket> buildAsync();
}
/**
! * A listener for events and messages on a {@code WebSocket}.
* {@Incubating}
*
! * <p> Each method of {@code Listener} corresponds to a type of event or a
! * type of message. The {@code WebSocket} argument of the method is the
! * {@code WebSocket} the event has occurred (the message has been received)
! * on. All methods with the same {@code WebSocket} argument are invoked in a
! * sequential
! * (and <a href="../../../java/util/concurrent/package-summary.html#MemoryVisibility">happens-before</a>)
! * order, one after another, possibly by different threads.
! *
! * <ul>
! * <li> {@link #onOpen(WebSocket) onOpen} <br>
! * This method is invoked first.
! * <li> {@link #onText(WebSocket, CharSequence, WebSocket.MessagePart)
! * onText}, {@link #onBinary(WebSocket, ByteBuffer, WebSocket.MessagePart)
! * onBinary}, {@link #onPing(WebSocket, ByteBuffer) onPing} and {@link
! * #onPong(WebSocket, ByteBuffer) onPong} <br>
! * These methods are invoked zero or more times after {@code onOpen}.
! * <li> {@link #onClose(WebSocket, int, String) onClose}, {@link
! * #onError(WebSocket, Throwable) onError} <br>
! * Only one of these methods is invoked, and that method is invoked last.
! * </ul>
! *
! * <p> Messages received by the {@code Listener} conform to the WebSocket
! * Protocol, otherwise {@code onError} with a {@link ProtocolException} is
! * invoked.
! *
! * <p> If a whole message is received, then the corresponding method
! * ({@code onText} or {@code onBinary}) will be invoked with {@link
! * WebSocket.MessagePart#WHOLE WHOLE} marker. Otherwise the method will be
! * invoked with {@link WebSocket.MessagePart#FIRST FIRST}, zero or more
! * times with {@link WebSocket.MessagePart#PART PART} and, finally, with
! * {@link WebSocket.MessagePart#LAST LAST} markers.
! *
! * If any of the methods above throws an exception, {@code onError} is then
! * invoked with the same {@code WebSocket} and this exception. Exceptions
! * thrown from {@code onError} or {@code onClose} are ignored.
! *
! * <p> When the method returns, the message is deemed received (in
! * particular, if contained in a {@code ByteBuffer buffer}, the data is
! * deemed received completely regardless of the result {@code
! * buffer.hasRemaining()} upon the method's return. After this further
! * messages may be received.
! *
! * <p> These invocations begin asynchronous processing which might not end
! * with the invocation. To provide coordination, methods of {@code Listener}
! * return a {@link CompletionStage CompletionStage}.
! * The {@code CompletionStage} signals the {@code WebSocket} that the
! * processing of a message has ended. For convenience, methods may return
! * {@code null}, which (by convention) means the same as returning an
! * already completed (normally) {@code CompletionStage}.
! * If the returned {@code CompletionStage} completes exceptionally, then
! * {@link #onError(WebSocket, Throwable) onError} will be invoked with the
! * same {@code WebSocket} and this exception.
! *
! * <p> Control of the message passes to the {@code Listener} with the
! * invocation of the method. Control of the message returns to the {@code
! * WebSocket} at the earliest of, either returning {@code null} from the
! * method, or the completion of the {@code CompletionStage} returned from
! * the method. The {@code WebSocket} does not access the message while it's
! * not in its control. The {@code Listener} must not access the message
! * after its control has been returned to the {@code WebSocket}.
! *
! * <p> A {@code WebSocket} implementation never invokes {@code Listener}'s
! * methods with {@code null}s as their arguments.
*
* @since 9
*/
interface Listener {
/**
! * Notifies the {@code Listener} that it is connected to the provided
! * {@code WebSocket}.
*
! * <p> The {@code onOpen} method does not correspond to any message from
! * the WebSocket Protocol. It is a synthetic event and the first {@code
! * Listener}'s method to be invoked.
! *
! * <p> This method is usually used to make an initial {@linkplain
! * WebSocket#request(long) request} for messages.
! *
! * <p> If an exception is thrown from this method then {@link
! * #onError(WebSocket, Throwable) onError} will be invoked with the same
! * {@code WebSocket} and this exception.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* }</pre>
*
* @param webSocket
! * the WebSocket
*/
default void onOpen(WebSocket webSocket) { webSocket.request(1); }
/**
! * Receives a Text message.
! *
! * <p> The {@code onText} method is invoked zero or more times between
! * {@code onOpen} and ({@code onClose} or {@code onError}).
*
! * <p> This message may be a partial UTF-16 sequence. However, the
! * concatenation of all messages through the last will be a whole UTF-16
! * sequence.
! *
! * <p> If an exception is thrown from this method or the returned {@code
! * CompletionStage} completes exceptionally, then {@link
! * #onError(WebSocket, Throwable) onError} will be invoked with the same
! * {@code WebSocket} and this exception.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
! * @implNote This implementation passes only complete UTF-16 sequences
! * to the {@code onText} method.
*
* @param webSocket
! * the WebSocket
* @param message
* the message
* @param part
* the part
*
! * @return a {@code CompletionStage} which completes when the message
! * processing is done; or {@code null} if already done
*/
default CompletionStage<?> onText(WebSocket webSocket,
CharSequence message,
MessagePart part) {
webSocket.request(1);
return null;
}
/**
! * Receives a Binary message.
*
! * <p> The {@code onBinary} method is invoked zero or more times
! * between {@code onOpen} and ({@code onClose} or {@code onError}).
! *
! * <p> If an exception is thrown from this method or the returned {@code
! * CompletionStage} completes exceptionally, then {@link
! * #onError(WebSocket, Throwable) onError} will be invoked with the same
! * {@code WebSocket} and this exception.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
* @param webSocket
! * the WebSocket
* @param message
* the message
* @param part
* the part
*
! * @return a {@code CompletionStage} which completes when the message
! * processing is done; or {@code null} if already done
*/
default CompletionStage<?> onBinary(WebSocket webSocket,
ByteBuffer message,
MessagePart part) {
webSocket.request(1);
return null;
}
/**
! * Receives a Ping message.
*
! * <p> A Ping message may be sent or received by either client or
! * server. It may serve either as a keepalive or as a means to verify
! * that the remote endpoint is still responsive.
! *
! * <p> The {@code WebSocket} handles Ping messages by replying with
! * appropriate Pong messages using a strategy of its choice, but within
! * the boundaries of the WebSocket Protocol. The {@code WebSocket} may
! * invoke {@code onPing} after handling a Ping message, before doing so
! * or in parallel with it. In other words no particular ordering is
! * guaranteed. If an error occurs while implementation handles this Ping
! * message, then {@code onError} will be invoked with this error. For
! * more details on handling Ping messages see RFC 6455 sections
! * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">5.5.2. Ping</a>
! * and
! * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">5.5.3. Pong</a>.
! *
! * <p> The message will consist of not more than {@code 125} bytes:
! * {@code message.remaining() <= 125}.
! *
! * <p> The {@code onPing} is invoked zero or more times in between
! * {@code onOpen} and ({@code onClose} or {@code onError}).
! *
! * <p> If an exception is thrown from this method or the returned {@code
! * CompletionStage} completes exceptionally, then {@link
! * #onError(WebSocket, Throwable) onError} will be invoked with this
! * exception.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
* @param webSocket
! * the WebSocket
* @param message
* the message
*
! * @return a {@code CompletionStage} which completes when the message
! * processing is done; or {@code null} if already done
*/
default CompletionStage<?> onPing(WebSocket webSocket,
ByteBuffer message) {
webSocket.request(1);
return null;
}
/**
! * Receives a Pong message.
*
! * <p> A Pong message may be unsolicited or may be received in response
! * to a previously sent Ping. In the latter case, the contents of the
! * Pong is identical to the originating Ping.
! *
! * <p> The message will consist of not more than {@code 125} bytes:
! * {@code message.remaining() <= 125}.
! *
! * <p> The {@code onPong} method is invoked zero or more times in
! * between {@code onOpen} and ({@code onClose} or {@code onError}).
! *
! * <p> If an exception is thrown from this method or the returned {@code
! * CompletionStage} completes exceptionally, then {@link
! * #onError(WebSocket, Throwable) onError} will be invoked with this
! * exception.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
* @param webSocket
! * the WebSocket
* @param message
* the message
*
! * @return a {@code CompletionStage} which completes when the message
! * processing is done; or {@code null} if already done
*/
default CompletionStage<?> onPong(WebSocket webSocket,
ByteBuffer message) {
webSocket.request(1);
return null;
}
/**
! * Receives a Close message.
! *
! * <p> A Close message consists of a status code and a reason for
! * closing. The status code is an integer in the range {@code 1000 <=
! * code <= 65535}. The {@code reason} is a short string that has an
! * UTF-8 representation not longer than {@code 123} bytes. For more
! * details on Close message, status codes and reason see RFC 6455 sections
! * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">5.5.1. Close</a>
! * and
! * <a href="https://tools.ietf.org/html/rfc6455#section-7.4">7.4. Status Codes</a>.
! *
! * <p> After the returned {@code CompletionStage} has completed
! * (normally or exceptionally), the {@code WebSocket} completes the
! * closing handshake by replying with an appropriate Close message.
! *
! * <p> This implementation replies with a Close message that has the
! * same code this message has and an empty reason.
! *
! * <p> {@code onClose} is the last invocation on the {@code Listener}.
! * It is invoked at most once, but after {@code onOpen}. If an exception
! * is thrown from this method, it is ignored.
! *
! * <p> The {@code WebSocket} will close at the earliest of completion of
! * the returned {@code CompletionStage} or sending a Close message. In
! * particular, if a Close message has been {@linkplain WebSocket#sendClose
! * sent} before, then this invocation completes the closing handshake
! * and by the time this method is invoked, the {@code WebSocket} will
! * have been closed.
*
! * @implSpec The default implementation of this method behaves as if:
*
! * <pre>{@code
! * return null;
! * }</pre>
*
* @param webSocket
! * the WebSocket
* @param statusCode
* the status code
* @param reason
* the reason
*
! * @return a {@code CompletionStage} which completes when the {@code
! * WebSocket} can be closed; or {@code null} if it can be closed immediately
! *
! * @see #NORMAL_CLOSURE
*/
default CompletionStage<?> onClose(WebSocket webSocket,
int statusCode,
String reason) {
return null;
}
/**
! * Notifies an I/O or protocol error has occurred.
*
! * <p> The {@code onError} method does not correspond to any message
! * from the WebSocket Protocol. It is a synthetic event and the last
! * {@code Listener}'s method to be invoked. It is invoked at most once
! * but after {@code onOpen}. If an exception is thrown from this method,
! * it is ignored.
! *
! * <p> Note that the WebSocket Protocol requires <i>some</i> errors
! * occur in the incoming destination must be fatal to the connection. In
! * such cases the implementation takes care of <i>Failing the WebSocket
! * Connection</i>: by the time {@code onError} is invoked, the {@code
! * WebSocket} will have been closed. Any outstanding or subsequent send
! * operation will complete exceptionally with an {@code IOException}.
! * For more details on Failing the WebSocket Connection see RFC 6455
! * section <a href="https://tools.ietf.org/html/rfc6455#section-7.1.7">7.1.7. Fail the WebSocket Connection</a>.
! *
! * @apiNote Errors associated with sending messages are reported to the
! * {@code CompletableFuture}s {@code sendX} methods return, rather than
! * to this this method.
*
! * @implSpec The default implementation of this method does nothing.
*
* @param webSocket
! * the WebSocket
* @param error
* the error
*/
default void onError(WebSocket webSocket, Throwable error) { }
}
/**
! * A marker used by {@link WebSocket.Listener} in cases where a partial
! * message may be received.
* {@Incubating}
*
- * @see Listener#onText(WebSocket, CharSequence, MessagePart)
- * @see Listener#onBinary(WebSocket, ByteBuffer, MessagePart)
- *
* @since 9
*/
enum MessagePart {
/**
! * The first part of a message in a sequence.
*/
FIRST,
/**
! * A middle part of a message in a sequence.
*/
PART,
/**
! * The last part of a message in a sequence.
*/
LAST,
/**
* A whole message consisting of a single part.
--- 127,484 ----
* @return this builder
*/
Builder header(String name, String value);
/**
! * Sets a timeout for establishing a WebSocket connection.
*
! * <p> If the connection is not established within the specified
! * duration then building of the {@code WebSocket} will fail with
! * {@link HttpTimeoutException}. If this method is not invoked then the
! * infinite timeout is assumed.
*
! * @param timeout
! * the timeout, non-{@linkplain Duration#isNegative() negative},
! * non-{@linkplain Duration#ZERO ZERO}
*
* @return this builder
*/
! Builder connectTimeout(Duration timeout);
/**
! * Sets a request for the given subprotocols.
*
! * <p> After the {@code WebSocket} has been built, the actual
! * subprotocol can be queried via
! * {@link WebSocket#getSubprotocol WebSocket.getSubprotocol()}.
! *
! * <p> Subprotocols are specified in the order of preference. The most
! * preferred subprotocol is specified first. If there are any additional
! * subprotocols they are enumerated from the most preferred to the least
! * preferred.
! *
! * <p> Subprotocols not conforming to the syntax of subprotocol
! * identifiers are illegal. If this method is not invoked then no
! * subprotocols will be requested.
*
! * @param mostPreferred
! * the most preferred subprotocol
! * @param lesserPreferred
! * the lesser preferred subprotocols
*
* @return this builder
*/
! Builder subprotocols(String mostPreferred, String... lesserPreferred);
/**
! * Builds a {@link WebSocket} connected to the given {@code URI} and
! * associated with the given {@code Listener}.
*
! * <p> Returns a {@code CompletableFuture} which will either complete
! * normally with the resulting {@code WebSocket} or complete
! * exceptionally with one of the following errors:
* <ul>
* <li> {@link IOException} -
* if an I/O error occurs
* <li> {@link WebSocketHandshakeException} -
* if the opening handshake fails
* <li> {@link HttpTimeoutException} -
* if the opening handshake does not complete within
! * the timeout
* <li> {@link InterruptedException} -
! * if the operation is interrupted
* <li> {@link SecurityException} -
! * if a security manager has been installed and it denies
! * {@link java.net.URLPermission access} to {@code uri}.
! * <a href="HttpRequest.html#securitychecks">Security checks</a>
! * contains more information relating to the security context
! * in which the the listener is invoked.
* <li> {@link IllegalArgumentException} -
! * if any of the arguments of this builder's methods are
! * illegal
* </ul>
*
+ * @param uri
+ * the WebSocket URI
+ * @param listener
+ * the listener
+ *
* @return a {@code CompletableFuture} with the {@code WebSocket}
*/
! CompletableFuture<WebSocket> buildAsync(URI uri, Listener listener);
}
/**
! * The receiving interface of {@code WebSocket}.
* {@Incubating}
*
! * <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> 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.
*
* @since 9
*/
interface Listener {
/**
! * A {@code WebSocket} has been connected.
*
! * <p> This is the first invocation and it is made at most once. This
! * method is typically used to make an initial request for messages.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* }</pre>
*
* @param webSocket
! * the WebSocket that has been connected
*/
default void onOpen(WebSocket webSocket) { webSocket.request(1); }
/**
! * A Text message has been received.
*
! * <p> If a whole message has been received, this method will be invoked
! * with {@code MessagePart.WHOLE} marker. Otherwise, it will be invoked
! * with {@code FIRST}, possibly a number of times with {@code PART} and,
! * finally, with {@code LAST} markers. If this message is partial, it
! * may be an incomplete UTF-16 sequence. However, the concatenation of
! * all messages through the last will be a complete UTF-16 sequence.
! *
! * <p> Return a {@code CompletionStage} which will be used by the
! * {@code WebSocket} as a signal it may reclaim the
! * {@code CharSequence}. Do not access the {@code CharSequence} after
! * this {@ode CompletionStage} has completed.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
! * @implNote This method is always invoked with character sequences
! * which are complete UTF-16 sequences.
*
* @param webSocket
! * the WebSocket on which the message has been received
* @param message
* the message
* @param part
* the part
*
! * @return a {@code CompletionStage} which completes when the
! * {@code CharSequence} may be reclaimed; or {@code null} if it may be
! * reclaimed immediately
*/
default CompletionStage<?> onText(WebSocket webSocket,
CharSequence message,
MessagePart part) {
webSocket.request(1);
return null;
}
/**
! * A Binary message has been received.
*
! * <p> If a whole message has been received, this method will be invoked
! * with {@code MessagePart.WHOLE} marker. Otherwise, it will be invoked
! * with {@code FIRST}, possibly a number of times with {@code PART} and,
! * finally, with {@code LAST} markers.
! *
! * <p> This message consists of bytes from the buffer's position to
! * its limit.
! *
! * <p> Return a {@code CompletionStage} which will be used by the
! * {@code WebSocket} as a signal it may reclaim the
! * {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
! * this {@ode CompletionStage} has completed.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
* @param webSocket
! * the WebSocket on which the message has been received
* @param message
* the message
* @param part
* the part
*
! * @return a {@code CompletionStage} which completes when the
! * {@code ByteBuffer} may be reclaimed; or {@code null} if it may be
! * reclaimed immediately
*/
default CompletionStage<?> onBinary(WebSocket webSocket,
ByteBuffer message,
MessagePart part) {
webSocket.request(1);
return null;
}
/**
! * A Ping message has been received.
! *
! * <p> The message consists of not more than {@code 125} bytes from
! * the buffer's position to its limit.
*
! * <p> Return a {@code CompletionStage} which will be used by the
! * {@code WebSocket} as a signal it may reclaim the
! * {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
! * this {@ode CompletionStage} has completed.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
* @param webSocket
! * the WebSocket on which the message has been received
* @param message
* the message
*
! * @return a {@code CompletionStage} which completes when the
! * {@code ByteBuffer} may be reclaimed; or {@code null} if it may be
! * reclaimed immediately
*/
default CompletionStage<?> onPing(WebSocket webSocket,
ByteBuffer message) {
webSocket.request(1);
return null;
}
/**
! * A Pong message has been received.
*
! * <p> The message consists of not more than {@code 125} bytes from
! * the buffer's position to its limit.
! *
! * <p> Return a {@code CompletionStage} which will be used by the
! * {@code WebSocket} as a signal it may reclaim the
! * {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
! * this {@ode CompletionStage} has completed.
*
* @implSpec The default implementation of this method behaves as if:
*
* <pre>{@code
* webSocket.request(1);
* return null;
* }</pre>
*
* @param webSocket
! * the WebSocket on which the message has been received
* @param message
* the message
*
! * @return a {@code CompletionStage} which completes when the
! * {@code ByteBuffer} may be reclaimed; or {@code null} if it may be
! * reclaimed immediately
*/
default CompletionStage<?> onPong(WebSocket webSocket,
ByteBuffer message) {
webSocket.request(1);
return null;
}
/**
! * A Close message has been received.
*
! * <p> This is the last invocation from the {@code WebSocket}. By the
! * time this invocation begins the {@code 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}.
*
! * <p> A Close message consists of a status code and a reason for
! * closing. The status code is an integer from the range
! * {@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.
*
* @param webSocket
! * the WebSocket on which the message has been received
* @param statusCode
* the status code
* @param reason
* the reason
*
! * @return a {@code CompletionStage} which completes when the
! * {@code WebSocket} may be closed; or {@code null} if it may be
! * closed immediately
*/
default CompletionStage<?> onClose(WebSocket webSocket,
int statusCode,
String reason) {
return null;
}
/**
! * An unrecoverable 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
! * 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}.
*
! * <p> If an exception is thrown from this method, resulting behavior is
! * undefined.
*
* @param webSocket
! * the WebSocket on which the error has occurred
* @param error
* the error
*/
default void onError(WebSocket webSocket, Throwable error) { }
}
/**
! * A marker used by {@link WebSocket.Listener} for identifying partial
! * messages.
* {@Incubating}
*
* @since 9
*/
enum MessagePart {
/**
! * The first part of a message.
*/
FIRST,
/**
! * A middle part of a message.
*/
PART,
/**
! * The last part of a message.
*/
LAST,
/**
* A whole message consisting of a single part.
*** 593,856 ****
}
/**
* Sends a Text message with characters from the given {@code CharSequence}.
*
! * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
! * normally when the message has been sent or completes exceptionally if an
! * error occurs.
! *
! * <p> The {@code CharSequence} must not be modified until the returned
! * {@code CompletableFuture} completes (either normally or exceptionally).
*
! * <p> The returned {@code CompletableFuture} can complete exceptionally
! * with:
* <ul>
* <li> {@link IllegalArgumentException} -
* if {@code message} is a malformed UTF-16 sequence
* <li> {@link IllegalStateException} -
! * if the {@code WebSocket} is closed;
! * or if a Close message has been sent;
! * or if there is an outstanding send operation;
! * or if a previous Binary message was sent with {@code isLast == false}
* <li> {@link IOException} -
! * if an I/O error occurs during this operation;
! * or if the {@code WebSocket} has been closed due to an error;
* </ul>
*
! * @implNote This implementation does not accept partial UTF-16 sequences.
! * In case such a sequence is passed, a returned {@code CompletableFuture}
! * completes exceptionally with {@code IOException}.
*
* @param message
* the message
* @param isLast
* {@code true} if this is the last part of the message,
* {@code false} otherwise
*
! * @return a {@code CompletableFuture} with this {@code WebSocket}
*/
CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast);
/**
* Sends a Binary message with bytes from the given {@code ByteBuffer}.
*
! * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
! * normally when the message has been sent or completes exceptionally if an
! * error occurs.
*
! * <p> The returned {@code CompletableFuture} can complete exceptionally
! * with:
* <ul>
* <li> {@link IllegalStateException} -
! * if the {@code WebSocket} is closed;
! * or if a Close message has been sent;
! * or if there is an outstanding send operation;
! * or if a previous Text message was sent with {@code isLast == false}
* <li> {@link IOException} -
! * if an I/O error occurs during this operation;
! * or if the {@code WebSocket} has been closed due to an error
* </ul>
*
* @param message
* the message
* @param isLast
* {@code true} if this is the last part of the message,
* {@code false} otherwise
*
! * @return a {@code CompletableFuture} with this {@code WebSocket}
*/
CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast);
/**
! * Sends a Ping message with bytes from the given ByteBuffer.
*
! * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
! * normally when the message has been sent or completes exceptionally if an
! * error occurs.
*
! * <p> A Ping message may be sent or received by either client or server.
! * It may serve either as a keepalive or as a means to verify that the
! * remote endpoint is still responsive.
! *
! * <p> The message must consist of not more than {@code 125} bytes: {@code
! * message.remaining() <= 125}.
! *
! * <p> The returned {@code CompletableFuture} can complete exceptionally
! * with:
* <ul>
* <li> {@link IllegalArgumentException} -
! * if {@code message.remaining() > 125}
* <li> {@link IllegalStateException} -
! * if the {@code WebSocket} is closed;
! * or if a Close message has been sent;
! * or if there is an outstanding send operation
* <li> {@link IOException} -
! * if an I/O error occurs during this operation;
! * or if the {@code WebSocket} has been closed due to an error
* </ul>
*
* @param message
* the message
*
! * @return a {@code CompletableFuture} with this {@code WebSocket}
*/
CompletableFuture<WebSocket> sendPing(ByteBuffer message);
/**
! * Sends a Pong message with bytes from the given ByteBuffer.
! *
! * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
! * normally when the message has been sent or completes exceptionally if an
! * error occurs.
! *
! * <p> A Pong message may be unsolicited or may be sent in response to a
! * previously received Ping. In latter case the contents of the Pong must be
! * identical to the originating Ping.
*
! * <p> The message must consist of not more than {@code 125} bytes: {@code
! * message.remaining() <= 125}.
*
! * <p> The returned {@code CompletableFuture} can complete exceptionally
! * with:
* <ul>
* <li> {@link IllegalArgumentException} -
! * if {@code message.remaining() > 125}
* <li> {@link IllegalStateException} -
! * if the {@code WebSocket} is closed;
! * or if a Close message has been sent;
! * or if there is an outstanding send operation
* <li> {@link IOException} -
! * if an I/O error occurs during this operation;
! * or if the {@code WebSocket} has been closed due to an error
* </ul>
*
* @param message
* the message
*
! * @return a {@code CompletableFuture} with this {@code WebSocket}
*/
CompletableFuture<WebSocket> sendPong(ByteBuffer message);
/**
! * Sends a Close message with the given status code and the reason.
*
! * <p> When this method has been invoked, no further messages can be sent.
*
! * <p> The {@code statusCode} is an integer in the range {@code 1000 <= code
! * <= 4999}. However, not all status codes may be legal in some
! * implementations. Regardless of an implementation,
! * <code>{@value jdk.incubator.http.WebSocket#NORMAL_CLOSURE}</code>
! * is always legal and {@code 1002}, {@code 1003}, {@code 1005}, {@code
! * 1006}, {@code 1007}, {@code 1009}, {@code 1010}, {@code 1012}, {@code
! * 1013} and {@code 1015} are always illegal codes.
! *
! * <p> The {@code reason} is a short string that must have an UTF-8
! * representation not longer than {@code 123} bytes. For more details on
! * Close message, status codes and reason see RFC 6455 sections
! * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">5.5.1. Close</a>
! * and
! * <a href="https://tools.ietf.org/html/rfc6455#section-7.4">7.4. Status Codes</a>.
! *
! * <p> The method returns a {@code CompletableFuture<WebSocket>} which
! * completes normally when the message has been sent or completes
! * exceptionally if an error occurs.
*
! * <p> The returned {@code CompletableFuture} can complete exceptionally
! * with:
* <ul>
* <li> {@link IllegalArgumentException} -
! * if the {@code statusCode} has an illegal value;
! * or if {@code reason} doesn't have an UTF-8 representation of
! * length {@code <= 123}
* <li> {@link IOException} -
! * if an I/O error occurs during this operation;
! * or the {@code WebSocket} has been closed due to an error
* </ul>
*
! * <p> If this method has already been invoked or the {@code WebSocket} is
! * closed, then subsequent invocations of this method have no effect and the
! * returned {@code CompletableFuture} completes normally.
! *
! * <p> If a Close message has been {@linkplain Listener#onClose(WebSocket,
! * int, String) received} before, then this invocation completes the closing
! * handshake and by the time the returned {@code CompletableFuture}
! * completes, the {@code WebSocket} will have been closed.
*
* @param statusCode
* the status code
* @param reason
* the reason
*
! * @return a {@code CompletableFuture} with this {@code WebSocket}
*/
CompletableFuture<WebSocket> sendClose(int statusCode, String reason);
/**
! * Allows {@code n} more messages to be received by the {@link Listener
! * Listener}.
*
! * <p> The actual number of received messages might be fewer if a Close
! * message is received, the {@code WebSocket} closes or an error occurs.
*
! * <p> A {@code WebSocket} that has just been built, hasn't requested
! * anything yet. Usually the initial request for messages is made in {@link
! * Listener#onOpen(jdk.incubator.http.WebSocket) Listener.onOpen}.
! *
! * <p> If the {@code WebSocket} is closed then invoking this method has no
! * effect.
! *
! * @implNote This implementation does not distinguish between partial and
! * whole messages, because it's not known beforehand how a message will be
! * received.
! *
! * <p> If a server sends more messages than requested, this implementation
! * queues up these messages on the TCP connection and may eventually force
! * the sender to stop sending through TCP flow control.
*
* @param n
! * the number of messages
*
* @throws IllegalArgumentException
! * if {@code n < 0}
*/
void request(long n);
/**
! * Returns a {@linkplain Builder#subprotocols(String, String...) subprotocol}
! * which has been chosen for this {@code WebSocket}.
*
! * @return a subprotocol, or an empty {@code String} if there is none
*/
String getSubprotocol();
/**
! * Tells whether the {@code WebSocket} is closed.
*
! * <p> When a {@code WebSocket} is closed no further messages can be sent or
! * received.
*
! * @return {@code true} if the {@code WebSocket} is closed,
! * {@code false} otherwise
*/
! boolean isClosed();
/**
! * Closes the {@code WebSocket} abruptly.
*
! * <p> This method may be invoked at any time. This method closes the
! * underlying TCP connection and puts the {@code WebSocket} into a closed
! * state.
*
! * <p> As the result {@link Listener#onClose(WebSocket, int, String)
! * Listener.onClose} will be invoked unless either {@code onClose} or {@link
! * Listener#onError(WebSocket, Throwable) onError} has been invoked before.
! * In which case no additional invocation will happen.
*
! * <p> If the {@code WebSocket} is already closed then invoking this method
! * has no effect.
*
! * @throws IOException
! * if an I/O error occurs
*/
! void abort() throws IOException;
}
--- 487,718 ----
}
/**
* 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> A {@code CompletableFuture} returned from this method can
! * complete exceptionally with:
* <ul>
* <li> {@link IllegalArgumentException} -
* if {@code message} is a malformed UTF-16 sequence
* <li> {@link IllegalStateException} -
! * if {@code sendClose} has been invoked
! * or if the previous message has not been sent yet
! * or if a previous Binary message was sent with
! * {@code isLast == false}
* <li> {@link IOException} -
! * if an I/O error occurs
* </ul>
*
! * @implNote If a partial UTF-16 sequence is passed to this method, a
! * {@code CompletableFuture} returned will complete exceptionally with
! * {@code IOException}.
*
* @param message
* the message
* @param isLast
* {@code true} if this is the last part of the message,
* {@code false} otherwise
*
! * @return a {@code CompletableFuture} that completes, with this {@code
! * WebSocket}, when the message has been sent
*/
CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast);
/**
* 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 {@code CompletableFuture} returned from this method can
! * complete exceptionally with:
* <ul>
* <li> {@link IllegalStateException} -
! * if {@code sendClose} has been invoked
! * or if the previous message has not been sent yet
! * or if a previous Text message was sent with
! * {@code isLast == false}
* <li> {@link IOException} -
! * if an I/O error occurs
* </ul>
*
* @param message
* the message
* @param isLast
* {@code true} if this is the last part of the message,
* {@code false} otherwise
*
! * @return a {@code CompletableFuture} that completes, with this {@code
! * WebSocket}, when the message has been sent
*/
CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast);
/**
! * Sends a Ping message with bytes from the given {@code ByteBuffer}.
*
! * <p> The message consists of not more than {@code 125} 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:
* <ul>
* <li> {@link IllegalArgumentException} -
! * if the message is too long
* <li> {@link IllegalStateException} -
! * if {@code sendClose} has been invoked
* <li> {@link IOException} -
! * if an I/O error occurs
* </ul>
*
* @param message
* the message
*
! * @return a {@code CompletableFuture} that completes, with this {@code
! * WebSocket}, when the Ping message has been sent
*/
CompletableFuture<WebSocket> sendPing(ByteBuffer message);
/**
! * Sends a Pong message with bytes from the given {@code ByteBuffer}.
*
! * <p> The message consists of not more than {@code 125} 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:
* <ul>
* <li> {@link IllegalArgumentException} -
! * if the message is too long
* <li> {@link IllegalStateException} -
! * if {@code sendClose} has been invoked
* <li> {@link IOException} -
! * if an I/O error occurs
* </ul>
*
* @param message
* the message
*
! * @return a {@code CompletableFuture} that completes, with this {@code
! * WebSocket}, when the Pong message has been sent
*/
CompletableFuture<WebSocket> sendPong(ByteBuffer message);
/**
! * Sends a Close message with the given status code and the reason,
! * initiating an orderly closure.
! *
! * <p> When this method returns the output will have been closed.
*
! * <p> The {@code statusCode} is an integer from the range
! * {@code 1000 <= code <= 4999}. Status codes {@code 1002}, {@code 1003},
! * {@code 1006}, {@code 1007}, {@code 1009}, {@code 1010}, {@code 1012},
! * {@code 1013} and {@code 1015} are illegal. Behaviour in respect to other
! * 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} or {@code reason} are illegal
* <li> {@link IOException} -
! * if an I/O error occurs
* </ul>
*
! * @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.
*
* @param statusCode
* the status code
* @param reason
* the reason
*
! * @return a {@code CompletableFuture} that completes, with this {@code
! * WebSocket}, when the Close message has been sent
*/
CompletableFuture<WebSocket> sendClose(int statusCode, String reason);
/**
! * Requests {@code n} more messages from this {@code WebSocket}.
*
! * <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> This method may be invoked at any time.
*
* @param n
! * the number of messages requested
*
* @throws IllegalArgumentException
! * if {@code n <= 0}
*/
void request(long n);
/**
! * Returns the subprotocol for this {@code WebSocket}.
! *
! * <p> This method may be invoked at any time.
*
! * @return the subprotocol for this {@code WebSocket}, or an empty
! * {@code String} if there's no subprotocol
*/
String getSubprotocol();
/**
! * Tells whether or not this {@code WebSocket} is permanently closed
! * for sending messages.
*
! * <p> If this method returns {@code true}, subsequent invocations will also
! * return {@code true}. This method may be invoked at any time.
*
! * @return {@code true} if closed, {@code false} otherwise
*/
! boolean isOutputClosed();
/**
! * Tells whether or not this {@code WebSocket} is permanently closed
! * for receiving messages.
*
! * <p> If this method returns {@code true}, subsequent invocations will also
! * return {@code true}. This method may be invoked at any time.
*
! * @return {@code true} if closed, {@code false} otherwise
! */
! boolean isInputClosed();
!
! /**
! * Closes this {@code WebSocket} abruptly.
*
! * <p> When this method returns both the input and output will have been
! * closed. This method may be invoked at any time. Subsequent invocations
! * 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}.
*/
! void abort();
}
< prev index next >