All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.webclient.api.HttpClientConfig Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2024 Oracle and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.helidon.webclient.api;

import java.net.URI;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import java.util.function.Supplier;

import io.helidon.builder.api.Prototype;
import io.helidon.common.Errors;
import io.helidon.common.Generated;
import io.helidon.common.HelidonServiceLoader;
import io.helidon.common.config.Config;
import io.helidon.common.media.type.ParserMode;
import io.helidon.common.socket.SocketOptions;
import io.helidon.common.uri.UriFragment;
import io.helidon.common.uri.UriQuery;
import io.helidon.http.Header;
import io.helidon.http.HeaderName;
import io.helidon.http.encoding.ContentEncodingContext;
import io.helidon.http.encoding.ContentEncodingContextConfig;
import io.helidon.http.media.MediaContext;
import io.helidon.http.media.MediaContextConfig;
import io.helidon.http.media.MediaSupport;
import io.helidon.webclient.spi.DnsResolver;
import io.helidon.webclient.spi.WebClientService;
import io.helidon.webclient.spi.WebClientServiceProvider;

/**
 * This can be used by any HTTP client version, and does not act as a factory, for easy extensibility.
 *
 * @see #builder()
 * @see #create()
 */
@Generated(value = "io.helidon.builder.codegen.BuilderCodegen", trigger = "io.helidon.webclient.api.HttpClientConfigBlueprint")
public interface HttpClientConfig extends HttpClientConfigBlueprint, Prototype.Api, HttpConfigBase {

    /**
     * Create a new fluent API builder to customize configuration.
     *
     * @return a new builder
     */
    static HttpClientConfig.Builder builder() {
        return new HttpClientConfig.Builder();
    }

    /**
     * Create a new fluent API builder from an existing instance.
     *
     * @param instance an existing instance used as a base for the builder
     * @return a builder based on an instance
     */
    static HttpClientConfig.Builder builder(HttpClientConfig instance) {
        return HttpClientConfig.builder().from(instance);
    }

    /**
     * Create a new instance from configuration.
     *
     * @param config used to configure the new instance
     * @return a new instance configured from configuration
     */
    static HttpClientConfig create(Config config) {
        return HttpClientConfig.builder().config(config).buildPrototype();
    }

    /**
     * Create a new instance with default values.
     *
     * @return a new instance
     */
    static HttpClientConfig create() {
        return HttpClientConfig.builder().buildPrototype();
    }

    /**
     * Fluent API builder base for {@link HttpClientConfig}.
     *
     * @param  type of the builder extending this abstract builder
     * @param  type of the prototype interface that would be built by {@link #buildPrototype()}
     */
    abstract class BuilderBase, PROTOTYPE extends HttpClientConfig> extends HttpConfigBase.BuilderBase implements Prototype.ConfiguredBuilder {

        private final List mediaSupports = new ArrayList<>();
        private final List services = new ArrayList<>();
        private final Map defaultHeadersMap = new LinkedHashMap<>();
        private final Set
headers = new LinkedHashSet<>(); private boolean isMediaSupportsMutated; private boolean isServicesMutated; private boolean relativeUris = false; private boolean sendExpectContinue = true; private boolean servicesDiscoverServices = true; private boolean shareConnectionCache = true; private ClientUri baseUri; private Config config; private ContentEncodingContext contentEncoding; private DnsAddressLookup dnsAddressLookup; private DnsResolver dnsResolver; private Duration readContinueTimeout = Duration.parse("PT1S"); private ExecutorService executor; private int connectionCacheSize = 256; private int maxInMemoryEntity = 131072; private MediaContext mediaContext = MediaContext.create(); private ParserMode mediaTypeParserMode = ParserMode.STRICT; private SocketOptions socketOptions; private UriFragment baseFragment; private UriQuery baseQuery; private WebClientCookieManager cookieManager; /** * Protected to support extensibility. */ protected BuilderBase() { } /** * Update this builder from an existing prototype instance. This method disables automatic service discovery. * * @param prototype existing prototype to update this builder from * @return updated builder instance */ public BUILDER from(HttpClientConfig prototype) { super.from(prototype); baseUri(prototype.baseUri()); baseQuery(prototype.baseQuery()); baseFragment(prototype.baseFragment()); socketOptions(prototype.socketOptions()); dnsResolver(prototype.dnsResolver()); dnsAddressLookup(prototype.dnsAddressLookup()); addDefaultHeadersMap(prototype.defaultHeadersMap()); addHeaders(prototype.headers()); mediaTypeParserMode(prototype.mediaTypeParserMode()); contentEncoding(prototype.contentEncoding()); mediaContext(prototype.mediaContext()); if (!isMediaSupportsMutated) { mediaSupports.clear(); } addMediaSupports(prototype.mediaSupports()); if (!isServicesMutated) { services.clear(); } addServices(prototype.services()); servicesDiscoverServices = false; relativeUris(prototype.relativeUris()); executor(prototype.executor()); sendExpectContinue(prototype.sendExpectContinue()); connectionCacheSize(prototype.connectionCacheSize()); cookieManager(prototype.cookieManager()); readContinueTimeout(prototype.readContinueTimeout()); shareConnectionCache(prototype.shareConnectionCache()); maxInMemoryEntity(prototype.maxInMemoryEntity()); return self(); } /** * Update this builder from an existing prototype builder instance. * * @param builder existing builder prototype to update this builder from * @return updated builder instance */ public BUILDER from(HttpClientConfig.BuilderBase builder) { super.from(builder); builder.baseUri().ifPresent(this::baseUri); builder.baseQuery().ifPresent(this::baseQuery); builder.baseFragment().ifPresent(this::baseFragment); builder.socketOptions().ifPresent(this::socketOptions); builder.dnsResolver().ifPresent(this::dnsResolver); builder.dnsAddressLookup().ifPresent(this::dnsAddressLookup); addDefaultHeadersMap(builder.defaultHeadersMap); addHeaders(builder.headers); mediaTypeParserMode(builder.mediaTypeParserMode()); builder.contentEncoding().ifPresent(this::contentEncoding); mediaContext(builder.mediaContext()); if (isMediaSupportsMutated) { if (builder.isMediaSupportsMutated) { addMediaSupports(builder.mediaSupports); } } else { mediaSupports.clear(); addMediaSupports(builder.mediaSupports); } if (isServicesMutated) { if (builder.isServicesMutated) { addServices(builder.services); } } else { services.clear(); addServices(builder.services); } servicesDiscoverServices = builder.servicesDiscoverServices; relativeUris(builder.relativeUris()); builder.executor().ifPresent(this::executor); sendExpectContinue(builder.sendExpectContinue()); connectionCacheSize(builder.connectionCacheSize()); builder.cookieManager().ifPresent(this::cookieManager); readContinueTimeout(builder.readContinueTimeout()); shareConnectionCache(builder.shareConnectionCache()); maxInMemoryEntity(builder.maxInMemoryEntity()); return self(); } /** * Base URI of the client. * * @param baseUri base URI to use, query is extracted to base query (if any) * @return updated builder instance */ public BUILDER baseUri(URI baseUri) { HttpClientConfigSupport.HttpCustomMethods.baseUri(this, baseUri); return self(); } /** * Base URI of the client. * * @param baseUri base URI to use, query is extracted to base query (if any) * @return updated builder instance */ public BUILDER baseUri(String baseUri) { HttpClientConfigSupport.HttpCustomMethods.baseUri(this, baseUri); return self(); } /** * Add a default header value. * * @param name name of the header * @param value value of the header * @return updated builder instance */ public BUILDER addHeader(HeaderName name, String value) { HttpClientConfigSupport.HttpCustomMethods.addHeader(this, name, value); return self(); } /** * Add a default header value. * * @param name name of the header * @param value value of the header * @return updated builder instance */ public BUILDER addHeader(HeaderName name, int value) { HttpClientConfigSupport.HttpCustomMethods.addHeader(this, name, value); return self(); } /** * Add a default header value. * * @param name name of the header * @param value value of the header * @return updated builder instance */ public BUILDER addHeader(HeaderName name, long value) { HttpClientConfigSupport.HttpCustomMethods.addHeader(this, name, value); return self(); } /** * Add default header value. This method is not optimal and should only be used when the header name is really * obtained from a string, in other cases, use an alternative with {@link io.helidon.http.HeaderName} * or {@link io.helidon.http.Header}. * * @param name name of the header * @param value value of the header * @return updated builder instance * @see #addHeader(io.helidon.http.Header) */ public BUILDER addHeader(String name, String value) { HttpClientConfigSupport.HttpCustomMethods.addHeader(this, name, value); return self(); } /** * Add default header value. This method is not optimal and should only be used when the header name is really * obtained from a string, in other cases, use an alternative with {@link io.helidon.http.HeaderName} * or {@link io.helidon.http.Header}. * * @param name name of the header * @param value value of the header * @return updated builder instance * @see #addHeader(io.helidon.http.Header) */ public BUILDER addHeader(String name, int value) { HttpClientConfigSupport.HttpCustomMethods.addHeader(this, name, value); return self(); } /** * Add default header value. This method is not optimal and should only be used when the header name is really * obtained from a string, in other cases, use an alternative with {@link io.helidon.http.HeaderName} * or {@link io.helidon.http.Header}. * * @param name name of the header * @param value value of the header * @return updated builder instance * @see #addHeader(io.helidon.http.Header) */ public BUILDER addHeader(String name, long value) { HttpClientConfigSupport.HttpCustomMethods.addHeader(this, name, value); return self(); } /** * Update builder from configuration (node of this type). * If a value is present in configuration, it would override currently configured values. * * @param config configuration instance used to obtain values to update this builder * @return updated builder instance */ @Override public BUILDER config(Config config) { Objects.requireNonNull(config); this.config = config; super.config(config); config.get("base-uri").map(HttpClientConfigBlueprint::createBaseUri).ifPresent(this::baseUri); config.get("socket-options").map(SocketOptions::create).ifPresent(this::socketOptions); config.get("default-headers").detach().asMap().ifPresent(this::defaultHeadersMap); config.get("media-type-parser-mode").as(ParserMode.class).ifPresent(this::mediaTypeParserMode); config.get("content-encoding").map(ContentEncodingContextConfig::create).ifPresent(this::contentEncoding); config.get("media-context").map(MediaContextConfig::create).ifPresent(this::mediaContext); config.get("relative-uris").as(Boolean.class).ifPresent(this::relativeUris); config.get("send-expect-continue").as(Boolean.class).ifPresent(this::sendExpectContinue); config.get("connection-cache-size").as(Integer.class).ifPresent(this::connectionCacheSize); config.get("cookie-manager").map(WebClientCookieManagerConfig::create).ifPresent(this::cookieManager); config.get("read-continue-timeout").as(Duration.class).ifPresent(this::readContinueTimeout); config.get("share-connection-cache").as(Boolean.class).ifPresent(this::shareConnectionCache); config.get("max-in-memory-entity").as(Integer.class).ifPresent(this::maxInMemoryEntity); return self(); } /** * Clear existing value of this property. * * @return updated builder instance * @see #baseUri() */ public BUILDER clearBaseUri() { this.baseUri = null; return self(); } /** * Base uri used by the client in all requests. * * @param baseUri base uri of the client requests * @return updated builder instance * @see #baseUri() */ public BUILDER baseUri(ClientUri baseUri) { Objects.requireNonNull(baseUri); this.baseUri = baseUri; return self(); } /** * Base uri used by the client in all requests. * * @param baseUriConfig base uri of the client requests * @return updated builder instance * @see #baseUri() */ public BUILDER baseUri(Config baseUriConfig) { Objects.requireNonNull(baseUriConfig); this.baseUri = HttpClientConfigBlueprint.createBaseUri(baseUriConfig); return self(); } /** * Clear existing value of this property. * * @return updated builder instance * @see #baseQuery() */ public BUILDER clearBaseQuery() { this.baseQuery = null; return self(); } /** * Base query used by the client in all requests. * * @param baseQuery base query of the client requests * @return updated builder instance * @see #baseQuery() */ public BUILDER baseQuery(UriQuery baseQuery) { Objects.requireNonNull(baseQuery); this.baseQuery = baseQuery; return self(); } /** * Clear existing value of this property. * * @return updated builder instance * @see #baseFragment() */ public BUILDER clearBaseFragment() { this.baseFragment = null; return self(); } /** * Base fragment used by the client in all requests (unless overwritten on * per-request basis). * * @param baseFragment fragment to use * @return updated builder instance * @see #baseFragment() */ public BUILDER baseFragment(UriFragment baseFragment) { Objects.requireNonNull(baseFragment); this.baseFragment = baseFragment; return self(); } /** * Socket options for connections opened by this client. * If there is a value explicitly configured on this type and on the socket options, * the one configured on this type's builder will win: *
    *
  • {@link #readTimeout()}
  • *
  • {@link #connectTimeout()}
  • *
* * @param socketOptions socket options * @return updated builder instance * @see #socketOptions() */ public BUILDER socketOptions(SocketOptions socketOptions) { Objects.requireNonNull(socketOptions); this.socketOptions = socketOptions; return self(); } /** * Socket options for connections opened by this client. * If there is a value explicitly configured on this type and on the socket options, * the one configured on this type's builder will win: *
    *
  • {@link #readTimeout()}
  • *
  • {@link #connectTimeout()}
  • *
* * @param consumer consumer of builder for * socket options * @return updated builder instance * @see #socketOptions() */ public BUILDER socketOptions(Consumer consumer) { Objects.requireNonNull(consumer); var builder = SocketOptions.builder(); consumer.accept(builder); this.socketOptions(builder.build()); return self(); } /** * Socket options for connections opened by this client. * If there is a value explicitly configured on this type and on the socket options, * the one configured on this type's builder will win: *
    *
  • {@link #readTimeout()}
  • *
  • {@link #connectTimeout()}
  • *
* * @param supplier supplier of * socket options * @return updated builder instance * @see #socketOptions() */ public BUILDER socketOptions(Supplier supplier) { Objects.requireNonNull(supplier); this.socketOptions(supplier.get()); return self(); } /** * DNS resolver to be used by this client. * * @param dnsResolver dns resolver * @return updated builder instance * @see #dnsResolver() */ public BUILDER dnsResolver(DnsResolver dnsResolver) { Objects.requireNonNull(dnsResolver); this.dnsResolver = dnsResolver; return self(); } /** * DNS address lookup preferences to be used by this client. * Default value is determined by capabilities of the system. * * @param dnsAddressLookup dns address lookup strategy * @return updated builder instance * @see #dnsAddressLookup() */ public BUILDER dnsAddressLookup(DnsAddressLookup dnsAddressLookup) { Objects.requireNonNull(dnsAddressLookup); this.dnsAddressLookup = dnsAddressLookup; return self(); } /** * This method replaces all values with the new ones. * * @param defaultHeadersMap default headers * @return updated builder instance * @see #defaultHeadersMap() */ public BUILDER defaultHeadersMap(Map defaultHeadersMap) { Objects.requireNonNull(defaultHeadersMap); this.defaultHeadersMap.clear(); this.defaultHeadersMap.putAll(defaultHeadersMap); return self(); } /** * This method keeps existing values, then puts all new values into the map. * * @param defaultHeadersMap default headers * @return updated builder instance * @see #defaultHeadersMap() */ public BUILDER addDefaultHeadersMap(Map defaultHeadersMap) { Objects.requireNonNull(defaultHeadersMap); this.defaultHeadersMap.putAll(defaultHeadersMap); return self(); } /** * Default headers to be used in every request. * * @param headers default headers * @return updated builder instance * @see #headers() */ public BUILDER headers(Set headers) { Objects.requireNonNull(headers); this.headers.clear(); this.headers.addAll(headers); return self(); } /** * Default headers to be used in every request. * * @param headers default headers * @return updated builder instance * @see #headers() */ public BUILDER addHeaders(Set headers) { Objects.requireNonNull(headers); this.headers.addAll(headers); return self(); } /** * Default headers to be used in every request. * * @param header default headers * @return updated builder instance * @see #headers() */ public BUILDER addHeader(Header header) { Objects.requireNonNull(header); this.headers.add(header); return self(); } /** * Configure media type parsing mode for HTTP {@code Content-Type} header. * * @param mediaTypeParserMode media type parsing mode * @return updated builder instance * @see #mediaTypeParserMode() */ public BUILDER mediaTypeParserMode(ParserMode mediaTypeParserMode) { Objects.requireNonNull(mediaTypeParserMode); this.mediaTypeParserMode = mediaTypeParserMode; return self(); } /** * Configure the listener specific {@link io.helidon.http.encoding.ContentEncodingContext}. * This method discards all previously registered ContentEncodingContext. * If no content encoding context is registered, default encoding context is used. * * @param contentEncoding content encoding context * @return updated builder instance * @see #contentEncoding() */ public BUILDER contentEncoding(ContentEncodingContext contentEncoding) { Objects.requireNonNull(contentEncoding); this.contentEncoding = contentEncoding; return self(); } /** * Configure the listener specific {@link io.helidon.http.encoding.ContentEncodingContext}. * This method discards all previously registered ContentEncodingContext. * If no content encoding context is registered, default encoding context is used. * * @param contentEncodingConfig content encoding context * @return updated builder instance * @see #contentEncoding() */ public BUILDER contentEncoding(ContentEncodingContextConfig contentEncodingConfig) { Objects.requireNonNull(contentEncodingConfig); this.contentEncoding = ContentEncodingContext.create(contentEncodingConfig); return self(); } /** * Configure the listener specific {@link io.helidon.http.encoding.ContentEncodingContext}. * This method discards all previously registered ContentEncodingContext. * If no content encoding context is registered, default encoding context is used. * * @param consumer consumer of builder for * content encoding context * @return updated builder instance * @see #contentEncoding() */ public BUILDER contentEncoding(Consumer consumer) { Objects.requireNonNull(consumer); var builder = ContentEncodingContextConfig.builder(); consumer.accept(builder); this.contentEncoding(builder.build()); return self(); } /** * Configure the listener specific {@link io.helidon.http.encoding.ContentEncodingContext}. * This method discards all previously registered ContentEncodingContext. * If no content encoding context is registered, default encoding context is used. * * @param supplier supplier of * content encoding context * @return updated builder instance * @see #contentEncoding() */ public BUILDER contentEncoding(Supplier supplier) { Objects.requireNonNull(supplier); this.contentEncoding(supplier.get()); return self(); } /** * Configure the listener specific {@link io.helidon.http.media.MediaContext}. * This method discards all previously registered MediaContext. * If no media context is registered, default media context is used. * * @param mediaContext media context * @return updated builder instance * @see #mediaContext() */ public BUILDER mediaContext(MediaContext mediaContext) { Objects.requireNonNull(mediaContext); this.mediaContext = mediaContext; return self(); } /** * Configure the listener specific {@link io.helidon.http.media.MediaContext}. * This method discards all previously registered MediaContext. * If no media context is registered, default media context is used. * * @param mediaContextConfig media context * @return updated builder instance * @see #mediaContext() */ public BUILDER mediaContext(MediaContextConfig mediaContextConfig) { Objects.requireNonNull(mediaContextConfig); this.mediaContext = MediaContext.create(mediaContextConfig); return self(); } /** * Configure the listener specific {@link io.helidon.http.media.MediaContext}. * This method discards all previously registered MediaContext. * If no media context is registered, default media context is used. * * @param consumer consumer of builder for * media context * @return updated builder instance * @see #mediaContext() */ public BUILDER mediaContext(Consumer consumer) { Objects.requireNonNull(consumer); var builder = MediaContextConfig.builder(); consumer.accept(builder); this.mediaContext(builder.build()); return self(); } /** * Configure the listener specific {@link io.helidon.http.media.MediaContext}. * This method discards all previously registered MediaContext. * If no media context is registered, default media context is used. * * @param supplier supplier of * media context * @return updated builder instance * @see #mediaContext() */ public BUILDER mediaContext(Supplier supplier) { Objects.requireNonNull(supplier); this.mediaContext(supplier.get()); return self(); } /** * Media supports (manually added). If both {@link #mediaContext()} and this is configured, * there will be a new context created from return of this method, with fallback of {@link #mediaContext()}. * * @param mediaSupports list of explicitly added media supports * @return updated builder instance * @see #mediaSupports() */ public BUILDER mediaSupports(List mediaSupports) { Objects.requireNonNull(mediaSupports); isMediaSupportsMutated = true; this.mediaSupports.clear(); this.mediaSupports.addAll(mediaSupports); return self(); } /** * Media supports (manually added). If both {@link #mediaContext()} and this is configured, * there will be a new context created from return of this method, with fallback of {@link #mediaContext()}. * * @param mediaSupports list of explicitly added media supports * @return updated builder instance * @see #mediaSupports() */ public BUILDER addMediaSupports(List mediaSupports) { Objects.requireNonNull(mediaSupports); isMediaSupportsMutated = true; this.mediaSupports.addAll(mediaSupports); return self(); } /** * Media supports (manually added). If both {@link #mediaContext()} and this is configured, * there will be a new context created from return of this method, with fallback of {@link #mediaContext()}. * * @param mediaSupport list of explicitly added media supports * @return updated builder instance * @see #mediaSupports() */ public BUILDER addMediaSupport(MediaSupport mediaSupport) { Objects.requireNonNull(mediaSupport); this.mediaSupports.add(mediaSupport); isMediaSupportsMutated = true; return self(); } /** * WebClient services. * * @param discoverServices whether to discover implementations through service loader * @return updated builder instance * @see #services() */ public BUILDER servicesDiscoverServices(boolean discoverServices) { this.servicesDiscoverServices = discoverServices; return self(); } /** * WebClient services. * * @param services services to use with this web client * @return updated builder instance * @see #services() */ public BUILDER services(List services) { Objects.requireNonNull(services); isServicesMutated = true; this.services.clear(); this.services.addAll(services); return self(); } /** * WebClient services. * * @param services services to use with this web client * @return updated builder instance * @see #services() */ public BUILDER addServices(List services) { Objects.requireNonNull(services); isServicesMutated = true; this.services.addAll(services); return self(); } /** * WebClient services. * * @param service services to use with this web client * @return updated builder instance * @see #services() */ public BUILDER addService(WebClientService service) { Objects.requireNonNull(service); this.services.add(service); isServicesMutated = true; return self(); } /** * Can be set to {@code true} to force the use of relative URIs in all requests, * regardless of the presence or absence of proxies or no-proxy lists. * * @param relativeUris relative URIs flag * @return updated builder instance * @see #relativeUris() */ public BUILDER relativeUris(boolean relativeUris) { this.relativeUris = relativeUris; return self(); } /** * Client executor service. * * @param executor executor service to use when needed (such as for HTTP/2) * @return updated builder instance * @see #executor() */ public BUILDER executor(ExecutorService executor) { Objects.requireNonNull(executor); this.executor = executor; return self(); } /** * Whether Expect-100-Continue header is sent to verify server availability before sending an entity. *

* Defaults to {@code true}. *

* * @param sendExpectContinue whether Expect:100-Continue header should be sent on streamed transfers * @return updated builder instance * @see #sendExpectContinue() */ public BUILDER sendExpectContinue(boolean sendExpectContinue) { this.sendExpectContinue = sendExpectContinue; return self(); } /** * Maximal size of the connection cache. * For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). * This option limits the size. Setting this number lower than the "usual" number of target services will cause connections * to be closed and reopened frequently. * * @param connectionCacheSize * @return updated builder instance * @see #connectionCacheSize() */ public BUILDER connectionCacheSize(int connectionCacheSize) { this.connectionCacheSize = connectionCacheSize; return self(); } /** * Clear existing value of this property. * * @return updated builder instance * @see #cookieManager() */ public BUILDER clearCookieManager() { this.cookieManager = null; return self(); } /** * WebClient cookie manager. * * @param cookieManager cookie manager to use * @return updated builder instance * @see #cookieManager() */ public BUILDER cookieManager(WebClientCookieManager cookieManager) { Objects.requireNonNull(cookieManager); this.cookieManager = cookieManager; return self(); } /** * WebClient cookie manager. * * @param cookieManagerConfig cookie manager to use * @return updated builder instance * @see #cookieManager() */ public BUILDER cookieManager(WebClientCookieManagerConfig cookieManagerConfig) { Objects.requireNonNull(cookieManagerConfig); this.cookieManager = WebClientCookieManager.create(cookieManagerConfig); return self(); } /** * WebClient cookie manager. * * @param consumer cookie manager to use * @return updated builder instance * @see #cookieManager() */ public BUILDER cookieManager(Consumer consumer) { Objects.requireNonNull(consumer); var builder = WebClientCookieManager.builder(); consumer.accept(builder); this.cookieManager(builder.build()); return self(); } /** * Socket 100-Continue read timeout. Default is 1 second. * This read timeout is used when 100-Continue is sent by the client, before it sends an entity. * * @param readContinueTimeout read 100-Continue timeout duration * @return updated builder instance * @see #readContinueTimeout() */ public BUILDER readContinueTimeout(Duration readContinueTimeout) { Objects.requireNonNull(readContinueTimeout); this.readContinueTimeout = readContinueTimeout; return self(); } /** * Whether to share connection cache between all the WebClient instances in JVM. * * @param shareConnectionCache true if connection cache is shared * @return updated builder instance * @see #shareConnectionCache() */ public BUILDER shareConnectionCache(boolean shareConnectionCache) { this.shareConnectionCache = shareConnectionCache; return self(); } /** * If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance. * If bigger, streaming will be used. *

* Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such * cases, this option is ignored. Default is 128Kb. * * @param maxInMemoryEntity maximal number of bytes to buffer in memory for supported writers * @return updated builder instance * @see #maxInMemoryEntity() */ public BUILDER maxInMemoryEntity(int maxInMemoryEntity) { this.maxInMemoryEntity = maxInMemoryEntity; return self(); } /** * Base uri used by the client in all requests. * * @return the base uri */ public Optional baseUri() { return Optional.ofNullable(baseUri); } /** * Base query used by the client in all requests. * * @return the base query */ public Optional baseQuery() { return Optional.ofNullable(baseQuery); } /** * Base fragment used by the client in all requests (unless overwritten on * per-request basis). * * @return the base fragment */ public Optional baseFragment() { return Optional.ofNullable(baseFragment); } /** * Socket options for connections opened by this client. * If there is a value explicitly configured on this type and on the socket options, * the one configured on this type's builder will win: *

    *
  • {@link #readTimeout()}
  • *
  • {@link #connectTimeout()}
  • *
* * @return the socket options */ public Optional socketOptions() { return Optional.ofNullable(socketOptions); } /** * DNS resolver to be used by this client. * * @return the dns resolver */ public Optional dnsResolver() { return Optional.ofNullable(dnsResolver); } /** * DNS address lookup preferences to be used by this client. * Default value is determined by capabilities of the system. * * @return the dns address lookup */ public Optional dnsAddressLookup() { return Optional.ofNullable(dnsAddressLookup); } /** * Default headers to be used in every request from configuration. * * @return the default headers map */ public Map defaultHeadersMap() { return defaultHeadersMap; } /** * Default headers to be used in every request. * * @return the headers */ public Set
headers() { return headers; } /** * Configure media type parsing mode for HTTP {@code Content-Type} header. * * @return the media type parser mode */ public ParserMode mediaTypeParserMode() { return mediaTypeParserMode; } /** * Configure the listener specific {@link io.helidon.http.encoding.ContentEncodingContext}. * This method discards all previously registered ContentEncodingContext. * If no content encoding context is registered, default encoding context is used. * * @return the content encoding */ public Optional contentEncoding() { return Optional.ofNullable(contentEncoding); } /** * Configure the listener specific {@link io.helidon.http.media.MediaContext}. * This method discards all previously registered MediaContext. * If no media context is registered, default media context is used. * * @return the media context */ public MediaContext mediaContext() { return mediaContext; } /** * Media supports (manually added). If both {@link #mediaContext()} and this is configured, * there will be a new context created from return of this method, with fallback of {@link #mediaContext()}. * * @return the media supports */ public List mediaSupports() { return mediaSupports; } /** * WebClient services. * * @return the services */ public List services() { return services; } /** * Can be set to {@code true} to force the use of relative URIs in all requests, * regardless of the presence or absence of proxies or no-proxy lists. * * @return the relative uris */ public boolean relativeUris() { return relativeUris; } /** * Client executor service. * * @return the executor */ public Optional executor() { return Optional.ofNullable(executor); } /** * Whether Expect-100-Continue header is sent to verify server availability before sending an entity. *

* Defaults to {@code true}. *

* * @return the send expect continue */ public boolean sendExpectContinue() { return sendExpectContinue; } /** * Maximal size of the connection cache. * For most HTTP protocols, we may cache connections to various endpoints for keep alive (or stream reuse in case of HTTP/2). * This option limits the size. Setting this number lower than the "usual" number of target services will cause connections * to be closed and reopened frequently. * * @return the connection cache size */ public int connectionCacheSize() { return connectionCacheSize; } /** * WebClient cookie manager. * * @return the cookie manager */ public Optional cookieManager() { return Optional.ofNullable(cookieManager); } /** * Socket 100-Continue read timeout. Default is 1 second. * This read timeout is used when 100-Continue is sent by the client, before it sends an entity. * * @return the read continue timeout */ public Duration readContinueTimeout() { return readContinueTimeout; } /** * Whether to share connection cache between all the WebClient instances in JVM. * * @return the share connection cache */ public boolean shareConnectionCache() { return shareConnectionCache; } /** * If the entity is expected to be smaller that this number of bytes, it would be buffered in memory to optimize performance. * If bigger, streaming will be used. *

* Note that for some entity types we cannot use streaming, as they are already fully in memory (String, byte[]), for such * cases, this option is ignored. Default is 128Kb. * * @return the max in memory entity */ public int maxInMemoryEntity() { return maxInMemoryEntity; } /** * If this instance was configured, this would be the config instance used. * * @return config node used to configure this builder, or empty if not configured */ public Optional config() { return Optional.ofNullable(config); } @Override public String toString() { return "HttpClientConfigBuilder{" + "baseUri=" + baseUri + "," + "baseQuery=" + baseQuery + "," + "baseFragment=" + baseFragment + "," + "socketOptions=" + socketOptions + "," + "dnsResolver=" + dnsResolver + "," + "dnsAddressLookup=" + dnsAddressLookup + "," + "defaultHeadersMap=" + defaultHeadersMap + "," + "headers=" + headers + "," + "mediaTypeParserMode=" + mediaTypeParserMode + "," + "contentEncoding=" + contentEncoding + "," + "mediaContext=" + mediaContext + "," + "mediaSupports=" + mediaSupports + "," + "services=" + services + "," + "relativeUris=" + relativeUris + "," + "executor=" + executor + "," + "sendExpectContinue=" + sendExpectContinue + "," + "connectionCacheSize=" + connectionCacheSize + "," + "cookieManager=" + cookieManager + "," + "readContinueTimeout=" + readContinueTimeout + "," + "shareConnectionCache=" + shareConnectionCache + "," + "maxInMemoryEntity=" + maxInMemoryEntity + "};" + super.toString(); } /** * Handles providers and decorators. */ @SuppressWarnings("unchecked") protected void preBuildPrototype() { super.preBuildPrototype(); var config = this.config == null ? Config.empty() : this.config; { var serviceLoader = HelidonServiceLoader.create(ServiceLoader.load(WebClientServiceProvider.class)); this.addServices(discoverServices(config, "services", serviceLoader, WebClientServiceProvider.class, WebClientService.class, servicesDiscoverServices, services)); } new HttpClientConfigSupport.HttpBuilderDecorator().decorate(this); } /** * Validates required properties. */ protected void validatePrototype() { super.validatePrototype(); Errors.Collector collector = Errors.collector(); if (socketOptions == null) { collector.fatal(getClass(), "Property \"socket-options\" must not be null, but not set"); } if (dnsResolver == null) { collector.fatal(getClass(), "Property \"dnsResolver\" must not be null, but not set"); } if (dnsAddressLookup == null) { collector.fatal(getClass(), "Property \"dnsAddressLookup\" must not be null, but not set"); } if (contentEncoding == null) { collector.fatal(getClass(), "Property \"content-encoding\" must not be null, but not set"); } if (executor == null) { collector.fatal(getClass(), "Property \"executor\" must not be null, but not set"); } collector.collect().checkValid(); } /** * Base uri used by the client in all requests. * * @param baseUri base uri of the client requests * @return updated builder instance * @see #baseUri() */ BUILDER baseUri(Optional baseUri) { Objects.requireNonNull(baseUri); this.baseUri = baseUri.map(io.helidon.webclient.api.ClientUri.class::cast).orElse(this.baseUri); return self(); } /** * Base query used by the client in all requests. * * @param baseQuery base query of the client requests * @return updated builder instance * @see #baseQuery() */ BUILDER baseQuery(Optional baseQuery) { Objects.requireNonNull(baseQuery); this.baseQuery = baseQuery.map(io.helidon.common.uri.UriQuery.class::cast).orElse(this.baseQuery); return self(); } /** * Base fragment used by the client in all requests (unless overwritten on * per-request basis). * * @param baseFragment fragment to use * @return updated builder instance * @see #baseFragment() */ BUILDER baseFragment(Optional baseFragment) { Objects.requireNonNull(baseFragment); this.baseFragment = baseFragment.map(io.helidon.common.uri.UriFragment.class::cast).orElse(this.baseFragment); return self(); } /** * WebClient cookie manager. * * @param cookieManager cookie manager to use * @return updated builder instance * @see #cookieManager() */ BUILDER cookieManager(Optional cookieManager) { Objects.requireNonNull(cookieManager); this.cookieManager = cookieManager.map(io.helidon.webclient.api.WebClientCookieManager.class::cast).orElse(this.cookieManager); return self(); } /** * Generated implementation of the prototype, can be extended by descendant prototype implementations. */ protected static class HttpClientConfigImpl extends HttpConfigBaseImpl implements HttpClientConfig { private final boolean relativeUris; private final boolean sendExpectContinue; private final boolean shareConnectionCache; private final ContentEncodingContext contentEncoding; private final DnsAddressLookup dnsAddressLookup; private final DnsResolver dnsResolver; private final Duration readContinueTimeout; private final ExecutorService executor; private final int connectionCacheSize; private final int maxInMemoryEntity; private final List mediaSupports; private final List services; private final Map defaultHeadersMap; private final MediaContext mediaContext; private final Optional baseFragment; private final Optional baseQuery; private final Optional baseUri; private final Optional cookieManager; private final ParserMode mediaTypeParserMode; private final Set

headers; private final SocketOptions socketOptions; /** * Create an instance providing a builder. * * @param builder extending builder base of this prototype */ protected HttpClientConfigImpl(HttpClientConfig.BuilderBase builder) { super(builder); this.baseUri = builder.baseUri(); this.baseQuery = builder.baseQuery(); this.baseFragment = builder.baseFragment(); this.socketOptions = builder.socketOptions().get(); this.dnsResolver = builder.dnsResolver().get(); this.dnsAddressLookup = builder.dnsAddressLookup().get(); this.defaultHeadersMap = Collections.unmodifiableMap(new LinkedHashMap<>(builder.defaultHeadersMap())); this.headers = Collections.unmodifiableSet(new LinkedHashSet<>(builder.headers())); this.mediaTypeParserMode = builder.mediaTypeParserMode(); this.contentEncoding = builder.contentEncoding().get(); this.mediaContext = builder.mediaContext(); this.mediaSupports = List.copyOf(builder.mediaSupports()); this.services = List.copyOf(builder.services()); this.relativeUris = builder.relativeUris(); this.executor = builder.executor().get(); this.sendExpectContinue = builder.sendExpectContinue(); this.connectionCacheSize = builder.connectionCacheSize(); this.cookieManager = builder.cookieManager(); this.readContinueTimeout = builder.readContinueTimeout(); this.shareConnectionCache = builder.shareConnectionCache(); this.maxInMemoryEntity = builder.maxInMemoryEntity(); } @Override public Optional baseUri() { return baseUri; } @Override public Optional baseQuery() { return baseQuery; } @Override public Optional baseFragment() { return baseFragment; } @Override public SocketOptions socketOptions() { return socketOptions; } @Override public DnsResolver dnsResolver() { return dnsResolver; } @Override public DnsAddressLookup dnsAddressLookup() { return dnsAddressLookup; } @Override public Map defaultHeadersMap() { return defaultHeadersMap; } @Override public Set
headers() { return headers; } @Override public ParserMode mediaTypeParserMode() { return mediaTypeParserMode; } @Override public ContentEncodingContext contentEncoding() { return contentEncoding; } @Override public MediaContext mediaContext() { return mediaContext; } @Override public List mediaSupports() { return mediaSupports; } @Override public List services() { return services; } @Override public boolean relativeUris() { return relativeUris; } @Override public ExecutorService executor() { return executor; } @Override public boolean sendExpectContinue() { return sendExpectContinue; } @Override public int connectionCacheSize() { return connectionCacheSize; } @Override public Optional cookieManager() { return cookieManager; } @Override public Duration readContinueTimeout() { return readContinueTimeout; } @Override public boolean shareConnectionCache() { return shareConnectionCache; } @Override public int maxInMemoryEntity() { return maxInMemoryEntity; } @Override public String toString() { return "HttpClientConfig{" + "baseUri=" + baseUri + "," + "baseQuery=" + baseQuery + "," + "baseFragment=" + baseFragment + "," + "socketOptions=" + socketOptions + "," + "dnsResolver=" + dnsResolver + "," + "dnsAddressLookup=" + dnsAddressLookup + "," + "defaultHeadersMap=" + defaultHeadersMap + "," + "headers=" + headers + "," + "mediaTypeParserMode=" + mediaTypeParserMode + "," + "contentEncoding=" + contentEncoding + "," + "mediaContext=" + mediaContext + "," + "mediaSupports=" + mediaSupports + "," + "services=" + services + "," + "relativeUris=" + relativeUris + "," + "executor=" + executor + "," + "sendExpectContinue=" + sendExpectContinue + "," + "connectionCacheSize=" + connectionCacheSize + "," + "cookieManager=" + cookieManager + "," + "readContinueTimeout=" + readContinueTimeout + "," + "shareConnectionCache=" + shareConnectionCache + "," + "maxInMemoryEntity=" + maxInMemoryEntity + "};" + super.toString(); } @Override public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof HttpClientConfig other)) { return false; } return super.equals(other) && Objects.equals(baseUri, other.baseUri()) && Objects.equals(baseQuery, other.baseQuery()) && Objects.equals(baseFragment, other.baseFragment()) && Objects.equals(socketOptions, other.socketOptions()) && Objects.equals(dnsResolver, other.dnsResolver()) && Objects.equals(dnsAddressLookup, other.dnsAddressLookup()) && Objects.equals(defaultHeadersMap, other.defaultHeadersMap()) && Objects.equals(headers, other.headers()) && Objects.equals(mediaTypeParserMode, other.mediaTypeParserMode()) && Objects.equals(contentEncoding, other.contentEncoding()) && Objects.equals(mediaContext, other.mediaContext()) && Objects.equals(mediaSupports, other.mediaSupports()) && Objects.equals(services, other.services()) && relativeUris == other.relativeUris() && Objects.equals(executor, other.executor()) && sendExpectContinue == other.sendExpectContinue() && connectionCacheSize == other.connectionCacheSize() && Objects.equals(cookieManager, other.cookieManager()) && Objects.equals(readContinueTimeout, other.readContinueTimeout()) && shareConnectionCache == other.shareConnectionCache() && maxInMemoryEntity == other.maxInMemoryEntity(); } @Override public int hashCode() { return 31 * super.hashCode() + Objects.hash(baseUri, baseQuery, baseFragment, socketOptions, dnsResolver, dnsAddressLookup, defaultHeadersMap, headers, mediaTypeParserMode, contentEncoding, mediaContext, mediaSupports, services, relativeUris, executor, sendExpectContinue, connectionCacheSize, cookieManager, readContinueTimeout, shareConnectionCache, maxInMemoryEntity); } } } /** * Fluent API builder for {@link HttpClientConfig}. */ class Builder extends HttpClientConfig.BuilderBase implements io.helidon.common.Builder { private Builder() { } @Override public HttpClientConfig buildPrototype() { preBuildPrototype(); validatePrototype(); return new HttpClientConfigImpl(this); } @Override public HttpClientConfig build() { return buildPrototype(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy