mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-22 20:14:43 +02:00
8204679: HTTP Client refresh
Co-authored-by: Daniel Fuchs <daniel.fuchs@oracle.com> Co-authored-by: Michael McMahon <michael.x.mcmahon@oracle.com> Co-authored-by: Pavel Rappo <pavel.rappo@oracle.com> Reviewed-by: chegar, dfuchs, michaelm
This commit is contained in:
parent
8c5dfa21b3
commit
659fdd8dc4
161 changed files with 8019 additions and 1853 deletions
|
@ -57,7 +57,7 @@ import jdk.internal.net.http.HttpClientBuilderImpl;
|
|||
* and can be used to send multiple requests.
|
||||
*
|
||||
* <p> An {@code HttpClient} provides configuration information, and resource
|
||||
* sharing, for all requests send through it.
|
||||
* sharing, for all requests sent through it.
|
||||
*
|
||||
* <p> A {@link BodyHandler BodyHandler} must be supplied for each {@link
|
||||
* HttpRequest} sent. The {@code BodyHandler} determines how to handle the
|
||||
|
@ -232,11 +232,10 @@ public abstract class HttpClient {
|
|||
*
|
||||
* <p> If this method is not invoked prior to {@linkplain #build()
|
||||
* building}, a default executor is created for each newly built {@code
|
||||
* HttpClient}. The default executor uses a {@linkplain
|
||||
* Executors#newCachedThreadPool(ThreadFactory) cached thread pool},
|
||||
* with a custom thread factory.
|
||||
* HttpClient}.
|
||||
*
|
||||
* @implNote If a security manager has been installed, the thread
|
||||
* @implNote The default executor uses a thread pool, with a custom
|
||||
* thread factory. If a security manager has been installed, the thread
|
||||
* factory creates threads that run with an access control context that
|
||||
* has no permissions.
|
||||
*
|
||||
|
@ -451,7 +450,7 @@ public abstract class HttpClient {
|
|||
* then the response, containing the {@code 3XX} response code, is returned,
|
||||
* where it can be handled manually.
|
||||
*
|
||||
* <p> {@code Redirect} policy is set via the {@linkplain
|
||||
* <p> {@code Redirect} policy is set through the {@linkplain
|
||||
* HttpClient.Builder#followRedirects(Redirect) Builder.followRedirects}
|
||||
* method.
|
||||
*
|
||||
|
|
|
@ -25,62 +25,68 @@
|
|||
|
||||
package java.net.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.BiPredicate;
|
||||
import static java.lang.String.CASE_INSENSITIVE_ORDER;
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A read-only view of a set of HTTP headers.
|
||||
*
|
||||
* <p> An {@code HttpHeaders} is not created directly, but rather returned from
|
||||
* an {@link HttpResponse HttpResponse}. Specific HTTP headers can be set for
|
||||
* {@linkplain HttpRequest requests} through the one of the request builder's
|
||||
* {@link HttpRequest.Builder#header(String, String) headers} methods.
|
||||
* <p> An {@code HttpHeaders} is not typically created directly, but rather
|
||||
* returned from an {@link HttpRequest#headers() HttpRequest} or an
|
||||
* {@link HttpResponse#headers() HttpResponse}. Specific HTTP headers can be
|
||||
* set for a {@linkplain HttpRequest request} through one of the request
|
||||
* builder's {@link HttpRequest.Builder#header(String, String) headers} methods.
|
||||
*
|
||||
* <p> The methods of this class ( that accept a String header name ), and the
|
||||
* Map returned by the {@link #map() map} method, operate without regard to
|
||||
* case when retrieving the header value.
|
||||
* {@code Map} returned by the {@link #map() map} method, operate without regard
|
||||
* to case when retrieving the header value(s).
|
||||
*
|
||||
* <p> An HTTP header name may appear more than once in the HTTP protocol. As
|
||||
* such, headers are represented as a name and a list of values. Each occurrence
|
||||
* of a header value is added verbatim, to the appropriate header name list,
|
||||
* without interpreting its value. In particular, {@code HttpHeaders} does not
|
||||
* perform any splitting or joining of comma separated header value strings. The
|
||||
* order of elements in a header value list is preserved when {@link
|
||||
* HttpRequest.Builder#header(String, String) building} a request. For
|
||||
* responses, the order of elements in a header value list is the order in which
|
||||
* they were received. The {@code Map} returned by the {@code map} method,
|
||||
* however, does not provide any guarantee with regard to the ordering of its
|
||||
* entries.
|
||||
*
|
||||
* <p> {@code HttpHeaders} instances are immutable.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public abstract class HttpHeaders {
|
||||
public final class HttpHeaders {
|
||||
|
||||
/**
|
||||
* Creates an HttpHeaders.
|
||||
*/
|
||||
protected HttpHeaders() {}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the first value of the given named
|
||||
* (and possibly multi-valued) header. If the header is not present, then
|
||||
* the returned {@code Optional} is empty.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes
|
||||
* {@code allValues(name).stream().findFirst()}
|
||||
* Returns an {@link Optional} containing the first header string value of
|
||||
* the given named (and possibly multi-valued) header. If the header is not
|
||||
* present, then the returned {@code Optional} is empty.
|
||||
*
|
||||
* @param name the header name
|
||||
* @return an {@code Optional<String>} for the first named value
|
||||
* @return an {@code Optional<String>} containing the first named header
|
||||
* string value, if present
|
||||
*/
|
||||
public Optional<String> firstValue(String name) {
|
||||
return allValues(name).stream().findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link OptionalLong} containing the first value of the
|
||||
* named header field. If the header is not present, then the Optional is
|
||||
* empty. If the header is present but contains a value that does not parse
|
||||
* as a {@code Long} value, then an exception is thrown.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes
|
||||
* {@code allValues(name).stream().mapToLong(Long::valueOf).findFirst()}
|
||||
* Returns an {@link OptionalLong} containing the first header string value
|
||||
* of the named header field. If the header is not present, then the
|
||||
* Optional is empty. If the header is present but contains a value that
|
||||
* does not parse as a {@code Long} value, then an exception is thrown.
|
||||
*
|
||||
* @param name the header name
|
||||
* @return an {@code OptionalLong}
|
||||
|
@ -92,23 +98,19 @@ public abstract class HttpHeaders {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable List of all of the values of the given named
|
||||
* header. Always returns a List, which may be empty if the header is not
|
||||
* present.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes, among other things, the
|
||||
* {@code map().get(name)} to retrieve the list of header values.
|
||||
* Returns an unmodifiable List of all of the header string values of the
|
||||
* given named header. Always returns a List, which may be empty if the
|
||||
* header is not present.
|
||||
*
|
||||
* @param name the header name
|
||||
* @return a List of String values
|
||||
* @return a List of headers string values
|
||||
*/
|
||||
public List<String> allValues(String name) {
|
||||
requireNonNull(name);
|
||||
List<String> values = map().get(name);
|
||||
// Making unmodifiable list out of empty in order to make a list which
|
||||
// throws UOE unconditionally
|
||||
return values != null ? values : unmodifiableList(emptyList());
|
||||
return values != null ? values : List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +118,9 @@ public abstract class HttpHeaders {
|
|||
*
|
||||
* @return the Map
|
||||
*/
|
||||
public abstract Map<String, List<String>> map();
|
||||
public Map<String,List<String>> map() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests this HTTP headers instance for equality with the given object.
|
||||
|
@ -149,7 +153,11 @@ public abstract class HttpHeaders {
|
|||
* @return the hash-code value for this HTTP headers
|
||||
*/
|
||||
public final int hashCode() {
|
||||
return map().hashCode();
|
||||
int h = 0;
|
||||
for (Map.Entry<String, List<String>> e : map().entrySet()) {
|
||||
h += entryHash(e);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,4 +173,93 @@ public abstract class HttpHeaders {
|
|||
sb.append(" }");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HTTP headers from the given map. The given map's key
|
||||
* represents the header name, and its value the list of string header
|
||||
* values for that header name.
|
||||
*
|
||||
* <p> An HTTP header name may appear more than once in the HTTP protocol.
|
||||
* Such, <i>multi-valued</i>, headers must be represented by a single entry
|
||||
* in the given map, whose entry value is a list that represents the
|
||||
* multiple header string values. Leading and trailing whitespaces are
|
||||
* removed from all string values retrieved from the given map and its lists
|
||||
* before processing. Only headers that, after filtering, contain at least
|
||||
* one, possibly empty string, value will be added to the HTTP headers.
|
||||
*
|
||||
* @apiNote The primary purpose of this method is for testing frameworks.
|
||||
* Per-request headers can be set through one of the {@code HttpRequest}
|
||||
* {@link HttpRequest.Builder#header(String, String) headers} methods.
|
||||
*
|
||||
* @param headerMap the map containing the header names and values
|
||||
* @param filter a filter that can be used to inspect each
|
||||
* header-name-and-value pair in the given map to determine if
|
||||
* it should, or should not, be added to the to the HTTP
|
||||
* headers
|
||||
* @return an HTTP headers instance containing the given headers
|
||||
* @throws NullPointerException if any of: {@code headerMap}, a key or value
|
||||
* in the given map, or an entry in the map's value list, or
|
||||
* {@code filter}, is {@code null}
|
||||
* @throws IllegalArgumentException if the given {@code headerMap} contains
|
||||
* any two keys that are equal ( without regard to case ); or if the
|
||||
* given map contains any key whose length, after trimming
|
||||
* whitespaces, is {@code 0}
|
||||
*/
|
||||
public static HttpHeaders of(Map<String,List<String>> headerMap,
|
||||
BiPredicate<String,String> filter) {
|
||||
requireNonNull(headerMap);
|
||||
requireNonNull(filter);
|
||||
return headersOf(headerMap, filter);
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
private static final HttpHeaders NO_HEADERS = new HttpHeaders(Map.of());
|
||||
|
||||
private final Map<String,List<String>> headers;
|
||||
|
||||
private HttpHeaders(Map<String,List<String>> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
private static final int entryHash(Map.Entry<String, List<String>> e) {
|
||||
String key = e.getKey();
|
||||
List<String> value = e.getValue();
|
||||
// we know that by construction key and values can't be null
|
||||
int keyHash = key.toLowerCase(Locale.ROOT).hashCode();
|
||||
int valueHash = value.hashCode();
|
||||
return keyHash ^ valueHash;
|
||||
}
|
||||
|
||||
// Returns a new HTTP headers after performing a structural copy and filtering.
|
||||
private static HttpHeaders headersOf(Map<String,List<String>> map,
|
||||
BiPredicate<String,String> filter) {
|
||||
TreeMap<String,List<String>> other = new TreeMap<>(CASE_INSENSITIVE_ORDER);
|
||||
TreeSet<String> notAdded = new TreeSet<>(CASE_INSENSITIVE_ORDER);
|
||||
ArrayList<String> tempList = new ArrayList<>();
|
||||
map.forEach((key, value) -> {
|
||||
String headerName = requireNonNull(key).trim();
|
||||
if (headerName.isEmpty()) {
|
||||
throw new IllegalArgumentException("empty key");
|
||||
}
|
||||
List<String> headerValues = requireNonNull(value);
|
||||
headerValues.forEach(headerValue -> {
|
||||
headerValue = requireNonNull(headerValue).trim();
|
||||
if (filter.test(headerName, headerValue)) {
|
||||
tempList.add(headerValue);
|
||||
}
|
||||
});
|
||||
|
||||
if (tempList.isEmpty()) {
|
||||
if (other.containsKey(headerName)
|
||||
|| notAdded.contains(headerName.toLowerCase(Locale.ROOT)))
|
||||
throw new IllegalArgumentException("duplicate key: " + headerName);
|
||||
notAdded.add(headerName.toLowerCase(Locale.ROOT));
|
||||
} else if (other.put(headerName, List.copyOf(tempList)) != null) {
|
||||
throw new IllegalArgumentException("duplicate key: " + headerName);
|
||||
}
|
||||
tempList.clear();
|
||||
});
|
||||
return other.isEmpty() ? NO_HEADERS : new HttpHeaders(unmodifiableMap(other));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,10 +89,12 @@ public abstract class HttpRequest {
|
|||
* <p> Instances of {@code HttpRequest.Builder} are created by calling {@link
|
||||
* HttpRequest#newBuilder(URI)} or {@link HttpRequest#newBuilder()}.
|
||||
*
|
||||
* <p> Each of the setter methods modifies the state of the builder
|
||||
* and returns the same instance. The methods are not synchronized and
|
||||
* should not be called from multiple threads without external
|
||||
* synchronization. The {@link #build() build} method returns a new
|
||||
* <p> The builder can be used to configure per-request state, such as: the
|
||||
* request URI, the request method (default is GET unless explicitly set),
|
||||
* specific request headers, etc. Each of the setter methods modifies the
|
||||
* state of the builder and returns the same instance. The methods are not
|
||||
* synchronized and should not be called from multiple threads without
|
||||
* external synchronization. The {@link #build() build} method returns a new
|
||||
* {@code HttpRequest} each time it is invoked. Once built an {@code
|
||||
* HttpRequest} is immutable, and can be sent multiple times.
|
||||
*
|
||||
|
|
|
@ -830,13 +830,13 @@ public interface HttpResponse<T> {
|
|||
* BodySubscriber} provides implementations of many common body subscribers.
|
||||
*
|
||||
* <p> The object acts as a {@link Flow.Subscriber}<{@link List}<{@link
|
||||
* ByteBuffer}>> to the HTTP client implementation, which publishes
|
||||
* unmodifiable lists of read-only ByteBuffers containing the response body.
|
||||
* The Flow of data, as well as the order of ByteBuffers in the Flow lists,
|
||||
* is a strictly ordered representation of the response body. Both the Lists
|
||||
* and the ByteBuffers, once passed to the subscriber, are no longer used by
|
||||
* the HTTP client. The subscriber converts the incoming buffers of data to
|
||||
* some higher-level Java type {@code T}.
|
||||
* ByteBuffer}>> to the HTTP Client implementation, which publishes
|
||||
* lists of ByteBuffers containing the response body. The Flow of data, as
|
||||
* well as the order of ByteBuffers in the Flow lists, is a strictly ordered
|
||||
* representation of the response body. Both the Lists and the ByteBuffers,
|
||||
* once passed to the subscriber, are no longer used by the HTTP Client. The
|
||||
* subscriber converts the incoming buffers of data to some higher-level
|
||||
* Java type {@code T}.
|
||||
*
|
||||
* <p> The {@link #getBody()} method returns a
|
||||
* {@link CompletionStage}<{@code T}> that provides the response body
|
||||
|
@ -859,6 +859,9 @@ public interface HttpResponse<T> {
|
|||
* may cause the underlying HTTP connection to be closed and prevent it
|
||||
* from being reused for subsequent operations.
|
||||
*
|
||||
* @implNote The flow of data containing the response body is immutable.
|
||||
* Specifically, it is a flow of unmodifiable lists of read-only ByteBuffers.
|
||||
*
|
||||
* @param <T> the response body type
|
||||
* @see BodySubscribers
|
||||
* @since 11
|
||||
|
@ -888,20 +891,20 @@ public interface HttpResponse<T> {
|
|||
*
|
||||
* <pre>{@code // Streams the response body to a File
|
||||
* HttpResponse<byte[]> response = client
|
||||
* .send(request, (statusCode, responseHeaders) -> BodySubscribers.ofByteArray());
|
||||
* .send(request, responseInfo -> BodySubscribers.ofByteArray());
|
||||
*
|
||||
* // Accumulates the response body and returns it as a byte[]
|
||||
* HttpResponse<byte[]> response = client
|
||||
* .send(request, (statusCode, responseHeaders) -> BodySubscribers.ofByteArray());
|
||||
* .send(request, responseInfo -> BodySubscribers.ofByteArray());
|
||||
*
|
||||
* // Discards the response body
|
||||
* HttpResponse<Void> response = client
|
||||
* .send(request, (statusCode, responseHeaders) -> BodySubscribers.discarding());
|
||||
* .send(request, responseInfo -> BodySubscribers.discarding());
|
||||
*
|
||||
* // Accumulates the response body as a String then maps it to its bytes
|
||||
* HttpResponse<byte[]> response = client
|
||||
* .send(request, (sc, hdrs) ->
|
||||
* BodySubscribers.mapping(BodySubscribers.ofString(), String::getBytes));
|
||||
* .send(request, responseInfo ->
|
||||
* BodySubscribers.mapping(BodySubscribers.ofString(UTF_8), String::getBytes));
|
||||
* }</pre>
|
||||
*
|
||||
* @since 11
|
||||
|
|
|
@ -35,9 +35,9 @@ import java.util.concurrent.CompletionStage;
|
|||
/**
|
||||
* A WebSocket Client.
|
||||
*
|
||||
* <p> {@code WebSocket} instances can be created via {@link WebSocket.Builder}.
|
||||
* <p> {@code WebSocket} instances are created through {@link WebSocket.Builder}.
|
||||
*
|
||||
* <p> WebSocket has an input and an output sides. These sides are independent
|
||||
* <p> WebSocket has an input and an output side. These sides are independent
|
||||
* from each other. A side can either be open or closed. Once closed, the side
|
||||
* remains closed. WebSocket messages are sent through a {@code WebSocket} and
|
||||
* received through a {@code WebSocket.Listener} associated with it. Messages
|
||||
|
@ -55,21 +55,22 @@ import java.util.concurrent.CompletionStage;
|
|||
*
|
||||
* <p> A receive method is any of the {@code onText}, {@code onBinary},
|
||||
* {@code onPing}, {@code onPong} and {@code onClose} methods of
|
||||
* {@code Listener}. A receive method initiates a receive operation and returns
|
||||
* a {@code CompletionStage} which completes once the operation has completed.
|
||||
* {@code Listener}. WebSocket initiates a receive operation by invoking a
|
||||
* receive method on the listener. The listener then must return a
|
||||
* {@code CompletionStage} which completes once the operation has completed.
|
||||
*
|
||||
* <p> A WebSocket maintains an <a id="counter">internal counter</a>.
|
||||
* This counter's value is a number of times the WebSocket has yet to invoke a
|
||||
* receive method. While this counter is zero the WebSocket does not invoke
|
||||
* receive methods. The counter is incremented by {@code n} when {@code
|
||||
* request(n)} is called. The counter is decremented by one when the WebSocket
|
||||
* invokes a receive method. {@code onOpen} and {@code onError} are not receive
|
||||
* methods. WebSocket invokes {@code onOpen} prior to any other methods on the
|
||||
* listener. WebSocket invokes {@code onOpen} at most once. WebSocket may invoke
|
||||
* {@code onError} at any given time. If the WebSocket invokes {@code onError}
|
||||
* or {@code onClose}, then no further listener's methods will be invoked, no
|
||||
* matter the value of the counter. For a newly built WebSocket the counter is
|
||||
* zero. A WebSocket invokes methods on the listener in a thread-safe manner.
|
||||
* <p> To control receiving of messages, a WebSocket maintains an
|
||||
* <a id="counter">internal counter</a>. This counter's value is a number of
|
||||
* times the WebSocket has yet to invoke a receive method. While this counter is
|
||||
* zero the WebSocket does not invoke receive methods. The counter is
|
||||
* incremented by {@code n} when {@code request(n)} is called. The counter is
|
||||
* decremented by one when the WebSocket invokes a receive method.
|
||||
* {@code onOpen} and {@code onError} are not receive methods. WebSocket invokes
|
||||
* {@code onOpen} prior to any other methods on the listener. WebSocket invokes
|
||||
* {@code onOpen} at most once. WebSocket may invoke {@code onError} at any
|
||||
* given time. If the WebSocket invokes {@code onError} or {@code onClose}, then
|
||||
* no further listener's methods will be invoked, no matter the value of the
|
||||
* counter. For a newly built WebSocket the counter is zero.
|
||||
*
|
||||
* <p> Unless otherwise stated, {@code null} arguments will cause methods
|
||||
* of {@code WebSocket} to throw {@code NullPointerException}, similarly,
|
||||
|
@ -105,13 +106,13 @@ public interface WebSocket {
|
|||
/**
|
||||
* A builder of {@linkplain WebSocket WebSocket Clients}.
|
||||
*
|
||||
* <p> A builder can be created by invoking the
|
||||
* {@link HttpClient#newWebSocketBuilder HttpClient.newWebSocketBuilder}
|
||||
* method. The intermediate (setter-like) methods change the state of the
|
||||
* builder and return the same builder they have been invoked on. If an
|
||||
* intermediate method is not invoked, an appropriate default value (or
|
||||
* behavior) will be assumed. A {@code Builder} is not safe for use by
|
||||
* multiple threads without external synchronization.
|
||||
* <p> Builders are created by invoking
|
||||
* {@link HttpClient#newWebSocketBuilder HttpClient.newWebSocketBuilder}.
|
||||
* The intermediate (setter-like) methods change the state of the builder
|
||||
* and return the same builder they have been invoked on. If an intermediate
|
||||
* method is not invoked, an appropriate default value (or behavior) will be
|
||||
* assumed. A {@code Builder} is not safe for use by multiple threads
|
||||
* without external synchronization.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
|
@ -155,7 +156,7 @@ public interface WebSocket {
|
|||
* Sets a request for the given subprotocols.
|
||||
*
|
||||
* <p> After the {@code WebSocket} has been built, the actual
|
||||
* subprotocol can be queried via
|
||||
* subprotocol can be queried through
|
||||
* {@link WebSocket#getSubprotocol WebSocket.getSubprotocol()}.
|
||||
*
|
||||
* <p> Subprotocols are specified in the order of preference. The most
|
||||
|
@ -218,11 +219,17 @@ public interface WebSocket {
|
|||
* The receiving interface of {@code WebSocket}.
|
||||
*
|
||||
* <p> A {@code WebSocket} invokes methods of the associated listener
|
||||
* passing itself as an argument. When data has been received, the
|
||||
* {@code WebSocket} invokes a receive method. Methods {@code onText},
|
||||
* {@code onBinary}, {@code onPing} and {@code onPong} must return a
|
||||
* {@code CompletionStage} that completes once the message has been received
|
||||
* by the listener.
|
||||
* passing itself as an argument. These methods are invoked in a thread-safe
|
||||
* manner, such that the next invocation may start only after the previous
|
||||
* one has finished.
|
||||
*
|
||||
* <p> When data has been received, the {@code WebSocket} invokes a receive
|
||||
* method. Methods {@code onText}, {@code onBinary}, {@code onPing} and
|
||||
* {@code onPong} must return a {@code CompletionStage} that completes once
|
||||
* the message has been received by the listener. 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.
|
||||
*
|
||||
* <p> An {@code IOException} raised in {@code WebSocket} will result in an
|
||||
* invocation of {@code onError} with that exception (if the input is not
|
||||
|
@ -231,11 +238,14 @@ public interface WebSocket {
|
|||
* exceptionally, the 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.
|
||||
* @apiNote The strict sequential order of invocations from
|
||||
* {@code WebSocket} to {@code Listener} means, in particular, that the
|
||||
* {@code Listener}'s methods are treated as non-reentrant. This means that
|
||||
* {@code Listener} implementations do not need to be concerned with
|
||||
* possible recursion or the order in which they invoke
|
||||
* {@code WebSocket.request} in relation to their processing logic.
|
||||
*
|
||||
* @apiNote Careful attention may be required if a listener is associated
|
||||
* <p> Careful attention may be required if a listener is associated
|
||||
* with more than a single {@code WebSocket}. In this case invocations
|
||||
* related to different instances of {@code WebSocket} may not be ordered
|
||||
* and may even happen concurrently.
|
||||
|
|
|
@ -28,7 +28,7 @@ package java.net.http;
|
|||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception used to signal the opening handshake failed.
|
||||
* Thrown when the opening handshake has failed.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
|
@ -55,6 +55,10 @@ public final class WebSocketHandshakeException extends IOException {
|
|||
* <p> The value may be unavailable ({@code null}) if this exception has
|
||||
* been serialized and then deserialized.
|
||||
*
|
||||
* @apiNote The primary purpose of this method is to allow programmatic
|
||||
* examination of the reasons behind the failure of the opening handshake.
|
||||
* Some of these reasons might allow recovery.
|
||||
*
|
||||
* @return server response
|
||||
*/
|
||||
public HttpResponse<?> getResponse() {
|
||||
|
|
|
@ -42,20 +42,24 @@
|
|||
* Hypertext Transfer Protocol (HTTP/1.1)</a>, and
|
||||
* <a href="https://tools.ietf.org/html/rfc6455">The WebSocket Protocol</a>.
|
||||
*
|
||||
* <p> Asynchronous tasks and dependent actions of returned {@link
|
||||
* java.util.concurrent.CompletableFuture} instances are executed on the threads
|
||||
* supplied by the client's {@link java.util.concurrent.Executor}, where
|
||||
* practical.
|
||||
* <p> In general, asynchronous tasks execute in either the thread invoking
|
||||
* the operation, e.g. {@linkplain HttpClient#send(HttpRequest, BodyHandler)
|
||||
* sending} an HTTP request, or by the threads supplied by the client's {@link
|
||||
* HttpClient#executor() executor}. Dependent tasks, those that are triggered by
|
||||
* returned CompletionStages or CompletableFutures, that do not explicitly
|
||||
* specify an executor, execute in the same {@link
|
||||
* CompletableFuture#defaultExecutor() default executor} as that of {@code
|
||||
* CompletableFuture}, or the invoking thread if the operation completes before
|
||||
* the dependent task is registered.
|
||||
*
|
||||
* <p> {@code CompletableFuture}s returned by this API will throw {@link
|
||||
* java.lang.UnsupportedOperationException} for their {@link
|
||||
* java.util.concurrent.CompletableFuture#obtrudeValue(Object) obtrudeValue}
|
||||
* and {@link java.util.concurrent.CompletableFuture#obtrudeException(Throwable)
|
||||
* obtrudeException} methods. Invoking the {@link
|
||||
* java.util.concurrent.CompletableFuture#cancel cancel} method on a {@code
|
||||
* CompletableFuture} returned by this API will not interrupt the underlying
|
||||
* operation, but may be useful to complete, exceptionally, dependent stages
|
||||
* that have not already completed.
|
||||
* UnsupportedOperationException} for their {@link
|
||||
* CompletableFuture#obtrudeValue(Object) obtrudeValue}
|
||||
* and {@link CompletableFuture#obtrudeException(Throwable)
|
||||
* obtrudeException} methods. Invoking the {@link CompletableFuture#cancel
|
||||
* cancel} method on a {@code CompletableFuture} returned by this API may not
|
||||
* interrupt the underlying operation, but may be useful to complete,
|
||||
* exceptionally, dependent stages that have not already completed.
|
||||
*
|
||||
* <p> Unless otherwise stated, {@code null} parameter values will cause methods
|
||||
* of all classes in this package to throw {@code NullPointerException}.
|
||||
|
@ -63,3 +67,9 @@
|
|||
* @since 11
|
||||
*/
|
||||
package java.net.http;
|
||||
|
||||
import java.lang.UnsupportedOperationException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse.BodyHandler;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue