From 6bb2e6dd976ef2aa5b6bf593a717489651832a5d Mon Sep 17 00:00:00 2001 From: Mohammad Noor Abu Khleif Date: Mon, 11 Mar 2024 13:28:29 +0300 Subject: [PATCH] feat: support connection and socket timeout configurations (#481) --- .../sdk/core/client/BaseRapidClient.kt | 13 +-- .../expediagroup/sdk/core/client/Client.kt | 80 +++++++++++++++++-- .../sdk/core/client/ExpediaGroupClient.kt | 18 ++--- .../core/configuration/ClientConfiguration.kt | 4 + .../ExpediaGroupClientConfiguration.kt | 4 + .../configuration/NetworkConfiguration.kt | 22 ----- .../configuration/RapidClientConfiguration.kt | 4 + .../collector/ConfigurationCollector.kt | 4 + .../provider/ConfigurationProvider.kt | 9 ++- .../ExpediaGroupConfigurationProvider.kt | 8 ++ .../provider/RapidConfigurationProvider.kt | 10 +++ .../provider/RuntimeConfigurationProvider.kt | 8 +- .../sdk/core/constant/ConfigurationName.kt | 4 + .../sdk/core/constant/Constant.kt | 6 +- .../provider/LoggingMessageProvider.kt | 5 ++ .../httptimeout/HttpTimeoutConfiguration.kt | 10 ++- .../plugin/httptimeout/HttpTimeoutPlugin.kt | 2 + .../ExpediaGroupClientConfigurationTest.kt | 28 ++++++- .../collector/ConfigurationCollectorTest.kt | 24 +++++- .../ExpediaGroupConfigurationProviderTest.kt | 6 +- .../RapidConfigurationProviderTest.kt | 6 +- detekt.yml | 1 + .../expediagroup-sdk/client/client.mustache | 2 +- 23 files changed, 211 insertions(+), 67 deletions(-) delete mode 100644 core/src/main/kotlin/com/expediagroup/sdk/core/configuration/NetworkConfiguration.kt diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseRapidClient.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseRapidClient.kt index 505795df9..c1b903440 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseRapidClient.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseRapidClient.kt @@ -51,16 +51,7 @@ abstract class BaseRapidClient( override val httpClient: HttpClient get() = _httpClient - /** - * A [BaseRapidClient] builder. - * - * @property key The API key to use for authentication. - * @property secret The API secret to use for authentication. - * @property endpoint The API endpoint to use for requests. - * @property requestTimeout The request timeout to be used. - * @property maskedLoggingHeaders The headers to be masked in logging. - * @property maskedLoggingBodyFields The body fields to be masked in logging. - */ + /** A [BaseRapidClient] builder. */ @Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients. - abstract class Builder> : com.expediagroup.sdk.core.client.Client.Builder() + abstract class Builder> : Client.Builder() } diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt index 9dd397f1a..eaaf668a6 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt @@ -90,6 +90,8 @@ abstract class Client( val endpoint: String = configurationProvider.endpoint ?: fireMissingConfigurationIssue(ConfigurationName.ENDPOINT) val authEndpoint: String = configurationProvider.authEndpoint ?: fireMissingConfigurationIssue(ConfigurationName.AUTH_ENDPOINT) val requestTimeout: Long = configurationProvider.requestTimeout ?: fireMissingConfigurationIssue(ConfigurationName.REQUEST_TIMEOUT_MILLIS) + val connectionTimeout: Long = configurationProvider.connectionTimeout ?: fireMissingConfigurationIssue(ConfigurationName.CONNECTION_TIMEOUT_MILLIS) + val socketTimeout: Long = configurationProvider.socketTimeout ?: fireMissingConfigurationIssue(ConfigurationName.SOCKET_TIMEOUT_MILLIS) val maskedLoggingHeaders: Set = configurationProvider.maskedLoggingHeaders ?: setOf() val maskedLoggingBodyFields: Set = configurationProvider.maskedLoggingBodyFields ?: setOf() @@ -107,7 +109,7 @@ abstract class Client( use(AuthenticationPlugin).with(authenticationConfiguration) use(DefaultRequestPlugin).with(DefaultRequestConfiguration.from(httpClientConfig, endpoint)) use(EncodingPlugin).with(EncodingConfiguration.from(httpClientConfig)) - use(HttpTimeoutPlugin).with(HttpTimeoutConfiguration.from(httpClientConfig, requestTimeout)) + use(HttpTimeoutPlugin).with(HttpTimeoutConfiguration.from(httpClientConfig, requestTimeout, connectionTimeout, socketTimeout)) use(ExceptionHandlingPlugin).with(ExceptionHandlingConfiguration.from(httpClientConfig)) } @@ -138,20 +140,48 @@ abstract class Client( /** * A [Client] builder. - * - * @property key The API key to use for authentication. - * @property secret The API secret to use for authentication. - * @property endpoint The API endpoint to use for requests. - * @property requestTimeout The request timeout to be used. - * @property maskedLoggingHeaders The headers to be masked in logging. - * @property maskedLoggingBodyFields The body fields to be masked in logging. */ abstract class Builder> { + /** Sets the API key to use for authentication. */ protected var key: String? = null + + /** Sets the API secret to use for authentication. */ protected var secret: String? = null + + /** Sets the API endpoint to use for requests. */ protected var endpoint: String? = null + + /** + * Sets the request timeout in milliseconds. + * + * Request timeout is the time period from the start of the request to the completion of the response. + * + * Default is infinite - no timeout. + */ protected var requestTimeout: Long? = null + + /** + * Sets the connection timeout in milliseconds. + * + * Connection timeout is the time period from the start of the request to the establishment of the connection with the server. + * + * Default is 10 seconds (10000 milliseconds). + */ + protected var connectionTimeout: Long? = null + + /** + * Sets the socket timeout in milliseconds. + * + * Socket timeout is the maximum period of inactivity between two consecutive data packets. + * + * Default is 15 seconds (15000 milliseconds). + */ + protected var socketTimeout: Long? = null + + /** Sets tne body fields to be masked in logging. */ protected var maskedLoggingHeaders: Set? = null + + /** Sets tne body fields to be masked in logging. */ protected var maskedLoggingBodyFields: Set? = null /** Sets the API key to use for authentication. @@ -181,17 +211,49 @@ abstract class Client( */ fun endpoint(endpoint: String): SELF { this.endpoint = endpoint.adhereTo(Contract.TRAILING_SLASH) + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.ENDPOINT, endpoint)) return self() } /** * Sets the request timeout in milliseconds. + * Request timeout is the time period from the start of the request to the completion of the response. + * Default is infinite - no timeout. * * @param milliseconds The request timeout to be used. * @return The [Builder] instance. */ fun requestTimeout(milliseconds: Long): SELF { this.requestTimeout = milliseconds + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.REQUEST_TIMEOUT_MILLIS, milliseconds.toString())) + return self() + } + + /** + * Sets the connection timeout in milliseconds. + * Connection timeout is the time period from the start of the request to the establishment of the connection with the server. + * Default is 10 seconds (10000 milliseconds). + * + * @param milliseconds The connection timeout to be used. + * @return The [Builder] instance. + */ + fun connectionTimeout(milliseconds: Long): SELF { + this.connectionTimeout = milliseconds + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.CONNECTION_TIMEOUT_MILLIS, milliseconds.toString())) + return self() + } + + /** + * Sets the socket timeout in milliseconds. + * Socket timeout is the maximum period of inactivity between two consecutive data packets. + * Default is 15 seconds (15000 milliseconds). + * + * @param milliseconds The socket timeout to be used. + * @return The [Builder] instance. + */ + fun socketTimeout(milliseconds: Long): SELF { + this.socketTimeout = milliseconds + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.SOCKET_TIMEOUT_MILLIS, milliseconds.toString())) return self() } @@ -203,6 +265,7 @@ abstract class Client( */ fun maskedLoggingHeaders(vararg headers: String): SELF { this.maskedLoggingHeaders = headers.toSet() + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_HEADERS, headers.joinToString())) return self() } @@ -214,6 +277,7 @@ abstract class Client( */ fun maskedLoggingBodyFields(vararg fields: String): SELF { this.maskedLoggingBodyFields = fields.toSet() + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_BODY_FIELDS, fields.joinToString())) return self() } diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/client/ExpediaGroupClient.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/client/ExpediaGroupClient.kt index f77310c47..e6ebae635 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/client/ExpediaGroupClient.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/client/ExpediaGroupClient.kt @@ -20,6 +20,7 @@ import com.expediagroup.sdk.core.configuration.collector.ConfigurationCollector import com.expediagroup.sdk.core.configuration.provider.ConfigurationProvider import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider import com.expediagroup.sdk.core.plugin.authentication.strategy.AuthenticationStrategy +import com.expediagroup.sdk.core.plugin.logging.ExpediaGroupLoggerFactory import io.ktor.client.HttpClient import io.ktor.client.engine.HttpClientEngine @@ -34,6 +35,10 @@ abstract class ExpediaGroupClient( clientConfiguration: ExpediaGroupClientConfiguration, httpClientEngine: HttpClientEngine = DEFAULT_HTTP_CLIENT_ENGINE ) : Client(namespace) { + companion object { + private val log = ExpediaGroupLoggerFactory.getLogger(this::class.java) + } + private val _configurationProvider: ConfigurationProvider = ConfigurationCollector.create( clientConfiguration.toProvider(), @@ -51,19 +56,10 @@ abstract class ExpediaGroupClient( override val httpClient: HttpClient get() = _httpClient - /** - * An [ExpediaGroupClient] builder. - * - * @property key The API key to use for requests. - * @property secret The API secret to use for requests. - * @property endpoint The API endpoint to use for requests. - * @property authEndpoint The API auth endpoint to use for requests. - * @property requestTimeout The request timeout to be used. - * @property maskedLoggingHeaders The headers to be masked in logging. - * @property maskedLoggingBodyFields The body fields to be masked in logging. - */ + /** An [ExpediaGroupClient] builder. */ @Suppress("unused") // This is used by the generated SDK clients. abstract class Builder> : Client.Builder() { + /** Sets the API auth endpoint to use for requests. */ protected var authEndpoint: String? = null /** Sets the API auth endpoint to use for requests. diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ClientConfiguration.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ClientConfiguration.kt index 7a57a773e..d8dfdedd9 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ClientConfiguration.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ClientConfiguration.kt @@ -22,6 +22,8 @@ interface ClientConfiguration { val secret: String? val endpoint: String? val requestTimeout: Long? + val connectionTimeout: Long? + val socketTimeout: Long? val maskedLoggingHeaders: Set? val maskedLoggingBodyFields: Set? @@ -32,6 +34,8 @@ interface ClientConfiguration { secret = secret, endpoint = endpoint, requestTimeout = requestTimeout, + connectionTimeout = connectionTimeout, + socketTimeout = socketTimeout, maskedLoggingHeaders = maskedLoggingHeaders, maskedLoggingBodyFields = maskedLoggingBodyFields ) diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfiguration.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfiguration.kt index c053a1b4f..e5289d9e9 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfiguration.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfiguration.kt @@ -25,6 +25,8 @@ import com.expediagroup.sdk.core.configuration.provider.RuntimeConfigurationProv * @property secret The API secret to use for authentication. * @property endpoint The API endpoint to use for requests. * @property requestTimeout The request timeout to be used in milliseconds. + * @property connectionTimeout The connection timeout to be used in milliseconds. + * @property socketTimeout The socket timeout to be used in milliseconds. * @property maskedLoggingHeaders The headers to be masked in logging. * @property maskedLoggingBodyFields The body fields to be masked in logging. * @property authEndpoint The API endpoint to use for authentication. @@ -34,6 +36,8 @@ data class ExpediaGroupClientConfiguration( override val secret: String? = null, override val endpoint: String? = null, override val requestTimeout: Long? = null, + override val connectionTimeout: Long? = null, + override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, override val maskedLoggingBodyFields: Set? = null, val authEndpoint: String? = null diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/NetworkConfiguration.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/NetworkConfiguration.kt deleted file mode 100644 index c79eea704..000000000 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/NetworkConfiguration.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2022 Expedia, Inc. - * - * 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 com.expediagroup.sdk.core.configuration - -internal data class NetworkConfiguration( - val connectionTimeout: Long = 10_000, - val readTimeout: Long = 10_000, - val writeTimeout: Long = 10_000 -) diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/RapidClientConfiguration.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/RapidClientConfiguration.kt index b2af07563..cac3637de 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/RapidClientConfiguration.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/RapidClientConfiguration.kt @@ -24,6 +24,8 @@ import com.expediagroup.sdk.core.client.BaseRapidClient * @property secret The API secret to use for authentication. * @property endpoint The API endpoint to use for requests. * @property requestTimeout The request timeout to be used in milliseconds. + * @property connectionTimeout The connection timeout to be used in milliseconds. + * @property socketTimeout The socket timeout to be used in milliseconds. * @property maskedLoggingHeaders The headers to be masked in logging. * @property maskedLoggingBodyFields The body fields to be masked in logging. */ @@ -32,6 +34,8 @@ data class RapidClientConfiguration( override val secret: String? = null, override val endpoint: String? = null, override val requestTimeout: Long? = null, + override val connectionTimeout: Long? = null, + override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, override val maskedLoggingBodyFields: Set? = null ) : ClientConfiguration diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollector.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollector.kt index 8bde34611..a83d40fbe 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollector.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollector.kt @@ -18,12 +18,14 @@ package com.expediagroup.sdk.core.configuration.collector import com.expediagroup.sdk.core.configuration.provider.ConfigurationProvider import com.expediagroup.sdk.core.constant.ConfigurationName.AUTH_ENDPOINT import com.expediagroup.sdk.core.constant.ConfigurationName.CONFIGURATION_COLLECTOR +import com.expediagroup.sdk.core.constant.ConfigurationName.CONNECTION_TIMEOUT_MILLIS import com.expediagroup.sdk.core.constant.ConfigurationName.ENDPOINT import com.expediagroup.sdk.core.constant.ConfigurationName.KEY import com.expediagroup.sdk.core.constant.ConfigurationName.MASKED_LOGGING_BODY_FIELDS import com.expediagroup.sdk.core.constant.ConfigurationName.MASKED_LOGGING_HEADERS import com.expediagroup.sdk.core.constant.ConfigurationName.REQUEST_TIMEOUT_MILLIS import com.expediagroup.sdk.core.constant.ConfigurationName.SECRET +import com.expediagroup.sdk.core.constant.ConfigurationName.SOCKET_TIMEOUT_MILLIS import com.expediagroup.sdk.core.constant.provider.LoggingMessageProvider import com.expediagroup.sdk.core.plugin.logging.ExpediaGroupLoggerFactory @@ -60,6 +62,8 @@ internal class ConfigurationCollector private constructor(providers: Configurati override val endpoint: String? = providers.firstWith { it.endpoint }.also { it?.log(ENDPOINT) }?.retrieve() override val authEndpoint: String? = providers.firstWith { it.authEndpoint }.also { it?.log(AUTH_ENDPOINT) }?.retrieve() override val requestTimeout: Long? = providers.firstWith { it.requestTimeout }.also { it?.log(REQUEST_TIMEOUT_MILLIS) }?.retrieve() + override val connectionTimeout: Long? = providers.firstWith { it.connectionTimeout }.also { it?.log(CONNECTION_TIMEOUT_MILLIS) }?.retrieve() + override val socketTimeout: Long? = providers.firstWith { it.socketTimeout }.also { it?.log(SOCKET_TIMEOUT_MILLIS) }?.retrieve() override val maskedLoggingHeaders: Set? = providers.firstWith { it.maskedLoggingHeaders }.also { it?.log(MASKED_LOGGING_HEADERS) }?.retrieve() override val maskedLoggingBodyFields: Set? = providers.firstWith { it.maskedLoggingBodyFields }.also { it?.log(MASKED_LOGGING_BODY_FIELDS) }?.retrieve() diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ConfigurationProvider.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ConfigurationProvider.kt index 6f110b1ea..ac7f7ea43 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ConfigurationProvider.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ConfigurationProvider.kt @@ -39,9 +39,14 @@ interface ConfigurationProvider { val authEndpoint: String? get() = Constant.EMPTY_STRING - /** The timeout to use for API requests. */ + /** The time period from the start of the request to the completion of the response. */ val requestTimeout: Long? - get() = Constant.TEN_SECONDS_IN_MILLIS + + /** The time period from the start of the request to the establishment of the connection with the server. */ + val connectionTimeout: Long? + + /** The maximum period of inactivity between two consecutive data packets. */ + val socketTimeout: Long? /** The headers to be masked in logging. */ val maskedLoggingHeaders: Set? diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProvider.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProvider.kt index b6a1e6fec..75295aeb2 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProvider.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProvider.kt @@ -16,9 +16,12 @@ package com.expediagroup.sdk.core.configuration.provider import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.authEndpoint +import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.connectionTimeout import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.endpoint import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.name import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.requestTimeout +import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfigurationProvider.socketTimeout +import com.expediagroup.sdk.core.constant.Constant /** * Default configuration provider for ExpediaGroup. @@ -27,9 +30,14 @@ import com.expediagroup.sdk.core.configuration.provider.ExpediaGroupConfiguratio * @property endpoint The API endpoint to use for requests. * @property authEndpoint The API endpoint to use for authentication. * @property requestTimeout The API response timeout to use for requests. + * @property connectionTimeout The connection timeout to be used in milliseconds. + * @property socketTimeout The socket timeout to be used in milliseconds. */ internal object ExpediaGroupConfigurationProvider : ConfigurationProvider { override val name: String = "ExpediaGroup Configuration Provider" override val endpoint: String = "https://api.expediagroup.com/" override val authEndpoint: String = "${endpoint}identity/oauth2/v3/token/" + override val requestTimeout: Long = Constant.INFINITE_TIMEOUT + override val connectionTimeout: Long = Constant.TEN_SECONDS_IN_MILLIS + override val socketTimeout: Long = Constant.FIFTEEN_SECONDS_IN_MILLIS } diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProvider.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProvider.kt index d0fe46c71..bc8e06c60 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProvider.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProvider.kt @@ -15,16 +15,26 @@ */ package com.expediagroup.sdk.core.configuration.provider +import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.connectionTimeout import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.endpoint import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.name +import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.requestTimeout +import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvider.socketTimeout +import com.expediagroup.sdk.core.constant.Constant /** * Default configuration provider for Rapid. * * @property name The name of the provider. * @property endpoint The API endpoint to use for requests. + * @property requestTimeout The API response timeout to use for requests. + * @property connectionTimeout The connection timeout to use for requests. + * @property socketTimeout The socket timeout to use for requests. */ internal object RapidConfigurationProvider : ConfigurationProvider { override val name: String = "Rapid Configuration Provider" override val endpoint: String = "https://api.ean.com/v3" + override val requestTimeout: Long = Constant.INFINITE_TIMEOUT + override val connectionTimeout: Long = Constant.TEN_SECONDS_IN_MILLIS + override val socketTimeout: Long = Constant.FIFTEEN_SECONDS_IN_MILLIS } diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RuntimeConfigurationProvider.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RuntimeConfigurationProvider.kt index 7de9cae4b..fd72dc58e 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RuntimeConfigurationProvider.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/provider/RuntimeConfigurationProvider.kt @@ -24,8 +24,10 @@ import com.expediagroup.sdk.core.constant.ConfigurationName.RUNTIME_CONFIGURATIO * @property key The API key to use for authentication. * @property secret The API secret to use for authentication. * @property endpoint The API endpoint to use for requests. - * @property requestTimeout The request timeout to be used in milliseconds. * @property authEndpoint The API endpoint to use for authentication. + * @property requestTimeout The request timeout to be used in milliseconds. + * @property connectionTimeout The connection timeout to be used in milliseconds. + * @property socketTimeout The socket timeout to be used in milliseconds. * @property maskedLoggingHeaders The headers to be masked in logging. * @property maskedLoggingBodyFields The body fields to be masked in logging. */ @@ -34,8 +36,10 @@ data class RuntimeConfigurationProvider( override val key: String? = null, override val secret: String? = null, override val endpoint: String? = null, - override val requestTimeout: Long? = null, override val authEndpoint: String? = null, + override val requestTimeout: Long? = null, + override val connectionTimeout: Long? = null, + override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, override val maskedLoggingBodyFields: Set? = null ) : ConfigurationProvider diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/constant/ConfigurationName.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/constant/ConfigurationName.kt index f77aa8083..0004086b7 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/constant/ConfigurationName.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/constant/ConfigurationName.kt @@ -26,6 +26,10 @@ internal object ConfigurationName { const val REQUEST_TIMEOUT_MILLIS = "request timeout in milliseconds" + const val CONNECTION_TIMEOUT_MILLIS = "connection timeout in milliseconds" + + const val SOCKET_TIMEOUT_MILLIS = "socket timeout in milliseconds" + const val MASKED_LOGGING_HEADERS = "masked logging headers" const val MASKED_LOGGING_BODY_FIELDS = "masked logging body fields" diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/constant/Constant.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/constant/Constant.kt index dc3195134..5f7a9d8c1 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/constant/Constant.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/constant/Constant.kt @@ -15,9 +15,13 @@ */ package com.expediagroup.sdk.core.constant +import io.ktor.client.plugins.HttpTimeout + internal object Constant { const val EMPTY_STRING = "" - const val TEN_SECONDS_IN_MILLIS = 10_000.toLong() + const val TEN_SECONDS_IN_MILLIS = 10_000L + const val FIFTEEN_SECONDS_IN_MILLIS = 15_000L + const val INFINITE_TIMEOUT = HttpTimeout.INFINITE_TIMEOUT_MS private const val SUCCESSFUL_STATUS_CODES_RANGE_START = 200 private const val SUCCESSFUL_STATUS_CODES_RANGE_END = 299 diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/constant/provider/LoggingMessageProvider.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/constant/provider/LoggingMessageProvider.kt index bf1e88262..f9d358ad3 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/constant/provider/LoggingMessageProvider.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/constant/provider/LoggingMessageProvider.kt @@ -30,6 +30,11 @@ internal object LoggingMessageProvider { providerName: String ) = "Successfully loaded [$property] from [$providerName]" + fun getRuntimeConfigurationProviderMessage( + property: String, + value: T + ) = "Setting [$property] to [$value] from runtime configuration provider" + fun getResponseBodyMessage( body: String, transactionId: String? diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutConfiguration.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutConfiguration.kt index fea16b029..a0d28f3cb 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutConfiguration.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutConfiguration.kt @@ -21,12 +21,16 @@ import io.ktor.client.engine.HttpClientEngineConfig internal data class HttpTimeoutConfiguration( override val httpClientConfiguration: HttpClientConfig, - val requestTimeout: Long + val requestTimeout: Long, + val connectionTimeout: Long, + val socketTimeout: Long ) : KtorPluginConfiguration(httpClientConfiguration) { companion object { fun from( httpClientConfig: HttpClientConfig, - requestTimeout: Long - ) = HttpTimeoutConfiguration(httpClientConfig, requestTimeout) + requestTimeout: Long, + connectionTimeout: Long, + socketTimeout: Long + ) = HttpTimeoutConfiguration(httpClientConfig, requestTimeout, connectionTimeout, socketTimeout) } } diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutPlugin.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutPlugin.kt index 9cf5200b4..0590d8847 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutPlugin.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/plugin/httptimeout/HttpTimeoutPlugin.kt @@ -26,6 +26,8 @@ internal object HttpTimeoutPlugin : Plugin { ) { configurations.httpClientConfiguration.install(HttpTimeout) { requestTimeoutMillis = configurations.requestTimeout + connectTimeoutMillis = configurations.connectionTimeout + socketTimeoutMillis = configurations.socketTimeout } } } diff --git a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfigurationTest.kt b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfigurationTest.kt index eefa36660..3310560e8 100644 --- a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfigurationTest.kt +++ b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/ExpediaGroupClientConfigurationTest.kt @@ -28,6 +28,10 @@ class ExpediaGroupClientConfigurationTest { assertNull(it.endpoint) assertNull(it.authEndpoint) assertNull(it.requestTimeout) + assertNull(it.connectionTimeout) + assertNull(it.socketTimeout) + assertNull(it.maskedLoggingHeaders) + assertNull(it.maskedLoggingBodyFields) } } @@ -38,13 +42,21 @@ class ExpediaGroupClientConfigurationTest { secret = "secret", endpoint = "endpoint", authEndpoint = "authEndpoint", - requestTimeout = 10_000 + requestTimeout = 10_000, + connectionTimeout = 5_000, + socketTimeout = 15_000, + maskedLoggingHeaders = setOf("header1", "header2"), + maskedLoggingBodyFields = setOf("field1", "field2") ).let { assertEquals("key", it.key) assertEquals("secret", it.secret) assertEquals("endpoint", it.endpoint) assertEquals("authEndpoint", it.authEndpoint) assertEquals(10_000, it.requestTimeout) + assertEquals(5_000, it.connectionTimeout) + assertEquals(15_000, it.socketTimeout) + assertEquals(setOf("header1", "header2"), it.maskedLoggingHeaders) + assertEquals(setOf("field1", "field2"), it.maskedLoggingBodyFields) } } @@ -56,6 +68,10 @@ class ExpediaGroupClientConfigurationTest { assertNull(it.endpoint) assertNull(it.authEndpoint) assertNull(it.requestTimeout) + assertNull(it.connectionTimeout) + assertNull(it.socketTimeout) + assertNull(it.maskedLoggingHeaders) + assertNull(it.maskedLoggingBodyFields) } } @@ -66,13 +82,21 @@ class ExpediaGroupClientConfigurationTest { secret = "secret", endpoint = "endpoint", authEndpoint = "authEndpoint", - requestTimeout = 10_000 + requestTimeout = 10_000, + connectionTimeout = 5_000, + socketTimeout = 15_000, + maskedLoggingHeaders = setOf("header1", "header2"), + maskedLoggingBodyFields = setOf("field1", "field2") ).toProvider().let { assertEquals("key", it.key) assertEquals("secret", it.secret) assertEquals("endpoint", it.endpoint) assertEquals("authEndpoint", it.authEndpoint) assertEquals(10_000, it.requestTimeout) + assertEquals(5_000, it.connectionTimeout) + assertEquals(15_000, it.socketTimeout) + assertEquals(setOf("header1", "header2"), it.maskedLoggingHeaders) + assertEquals(setOf("field1", "field2"), it.maskedLoggingBodyFields) } } } diff --git a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollectorTest.kt b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollectorTest.kt index aaed62559..af88c9795 100644 --- a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollectorTest.kt +++ b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/collector/ConfigurationCollectorTest.kt @@ -34,6 +34,10 @@ internal class ConfigurationCollectorTest { assertNull(collector.endpoint) assertNull(collector.authEndpoint) assertNull(collector.requestTimeout) + assertNull(collector.connectionTimeout) + assertNull(collector.socketTimeout) + assertNull(collector.maskedLoggingHeaders) + assertNull(collector.maskedLoggingBodyFields) } @Test @@ -55,7 +59,11 @@ internal class ConfigurationCollectorTest { secret = CLIENT_SECRET_TEST_CREDENTIAL, endpoint = ExpediaGroupConfigurationProvider.endpoint, authEndpoint = ExpediaGroupConfigurationProvider.authEndpoint, - requestTimeout = ExpediaGroupConfigurationProvider.requestTimeout + requestTimeout = ExpediaGroupConfigurationProvider.requestTimeout, + connectionTimeout = ExpediaGroupConfigurationProvider.connectionTimeout, + socketTimeout = ExpediaGroupConfigurationProvider.socketTimeout, + maskedLoggingHeaders = ExpediaGroupConfigurationProvider.maskedLoggingHeaders, + maskedLoggingBodyFields = ExpediaGroupConfigurationProvider.maskedLoggingBodyFields ) val collector = @@ -68,6 +76,10 @@ internal class ConfigurationCollectorTest { assertEquals(ExpediaGroupConfigurationProvider.endpoint, collector.endpoint) assertEquals(ExpediaGroupConfigurationProvider.authEndpoint, collector.authEndpoint) assertEquals(ExpediaGroupConfigurationProvider.requestTimeout, collector.requestTimeout) + assertEquals(ExpediaGroupConfigurationProvider.connectionTimeout, collector.connectionTimeout) + assertEquals(ExpediaGroupConfigurationProvider.socketTimeout, collector.socketTimeout) + assertEquals(ExpediaGroupConfigurationProvider.maskedLoggingHeaders, collector.maskedLoggingHeaders) + assertEquals(ExpediaGroupConfigurationProvider.maskedLoggingBodyFields, collector.maskedLoggingBodyFields) } @Test @@ -89,6 +101,10 @@ internal class ConfigurationCollectorTest { assertEquals(ExpediaGroupConfigurationProvider.endpoint, collector.endpoint) assertNull(collector.authEndpoint) assertNull(collector.requestTimeout) + assertNull(collector.connectionTimeout) + assertNull(collector.socketTimeout) + assertNull(collector.maskedLoggingHeaders) + assertNull(collector.maskedLoggingBodyFields) } @Test @@ -109,6 +125,10 @@ internal class ConfigurationCollectorTest { assertEquals(CLIENT_SECRET_TEST_CREDENTIAL, collector.secret) // from client configuration assertEquals(ExpediaGroupConfigurationProvider.endpoint, collector.endpoint) // from client configuration assertEquals(ExpediaGroupConfigurationProvider.authEndpoint, collector.authEndpoint) // from default provider - assertEquals(ExpediaGroupConfigurationProvider.requestTimeout, collector.requestTimeout) + assertEquals(ExpediaGroupConfigurationProvider.requestTimeout, collector.requestTimeout) // from default provider + assertEquals(ExpediaGroupConfigurationProvider.connectionTimeout, collector.connectionTimeout) // from default provider + assertEquals(ExpediaGroupConfigurationProvider.socketTimeout, collector.socketTimeout) // from default provider + assertEquals(ExpediaGroupConfigurationProvider.maskedLoggingHeaders, collector.maskedLoggingHeaders) // from default provider + assertEquals(ExpediaGroupConfigurationProvider.maskedLoggingBodyFields, collector.maskedLoggingBodyFields) // from default provider } } diff --git a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProviderTest.kt b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProviderTest.kt index 4227430ce..cbd45f931 100644 --- a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProviderTest.kt +++ b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/ExpediaGroupConfigurationProviderTest.kt @@ -16,6 +16,8 @@ package com.expediagroup.sdk.core.configuration.provider import com.expediagroup.sdk.core.constant.Constant.EMPTY_STRING +import com.expediagroup.sdk.core.constant.Constant.FIFTEEN_SECONDS_IN_MILLIS +import com.expediagroup.sdk.core.constant.Constant.INFINITE_TIMEOUT import com.expediagroup.sdk.core.constant.Constant.TEN_SECONDS_IN_MILLIS import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -27,6 +29,8 @@ internal class ExpediaGroupConfigurationProviderTest { assertEquals(EMPTY_STRING, ExpediaGroupConfigurationProvider.secret) assertEquals("https://api.expediagroup.com/", ExpediaGroupConfigurationProvider.endpoint) assertEquals("https://api.expediagroup.com/identity/oauth2/v3/token/", ExpediaGroupConfigurationProvider.authEndpoint) - assertEquals(TEN_SECONDS_IN_MILLIS, ExpediaGroupConfigurationProvider.requestTimeout) + assertEquals(INFINITE_TIMEOUT, ExpediaGroupConfigurationProvider.requestTimeout) + assertEquals(TEN_SECONDS_IN_MILLIS, ExpediaGroupConfigurationProvider.connectionTimeout) + assertEquals(FIFTEEN_SECONDS_IN_MILLIS, ExpediaGroupConfigurationProvider.socketTimeout) } } diff --git a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProviderTest.kt b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProviderTest.kt index b1e6dc0f4..7b9f22de7 100644 --- a/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProviderTest.kt +++ b/core/src/test/kotlin/com/expediagroup/sdk/core/configuration/provider/RapidConfigurationProviderTest.kt @@ -16,6 +16,8 @@ package com.expediagroup.sdk.core.configuration.provider import com.expediagroup.sdk.core.constant.Constant.EMPTY_STRING +import com.expediagroup.sdk.core.constant.Constant.FIFTEEN_SECONDS_IN_MILLIS +import com.expediagroup.sdk.core.constant.Constant.INFINITE_TIMEOUT import com.expediagroup.sdk.core.constant.Constant.TEN_SECONDS_IN_MILLIS import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -27,6 +29,8 @@ internal class RapidConfigurationProviderTest { assertEquals(EMPTY_STRING, RapidConfigurationProvider.secret) assertEquals("https://api.ean.com/v3", RapidConfigurationProvider.endpoint) assertEquals(EMPTY_STRING, RapidConfigurationProvider.authEndpoint) - assertEquals(TEN_SECONDS_IN_MILLIS, RapidConfigurationProvider.requestTimeout) + assertEquals(INFINITE_TIMEOUT, RapidConfigurationProvider.requestTimeout) + assertEquals(TEN_SECONDS_IN_MILLIS, RapidConfigurationProvider.connectionTimeout) + assertEquals(FIFTEEN_SECONDS_IN_MILLIS, RapidConfigurationProvider.socketTimeout) } } diff --git a/detekt.yml b/detekt.yml index eb61d840b..8262af552 100644 --- a/detekt.yml +++ b/detekt.yml @@ -1,6 +1,7 @@ style: MaxLineLength: maxLineLength: 200 + excludeCommentStatements: true ClassOrdering: active: false ReturnCount: diff --git a/generator/openapi/src/main/resources/templates/expediagroup-sdk/client/client.mustache b/generator/openapi/src/main/resources/templates/expediagroup-sdk/client/client.mustache index 30e3d3b53..bd7bdf9e4 100644 --- a/generator/openapi/src/main/resources/templates/expediagroup-sdk/client/client.mustache +++ b/generator/openapi/src/main/resources/templates/expediagroup-sdk/client/client.mustache @@ -19,7 +19,7 @@ import {{import}} class Builder : {{>partials/clientBase}}.Builder() { override fun build(): {{classname}} = {{classname}}( - {{>partials/clientConfiguration}}(key, secret, endpoint, requestTimeout, maskedLoggingHeaders, maskedLoggingBodyFields {{>partials/authEndpoint}}) + {{>partials/clientConfiguration}}(key, secret, endpoint, requestTimeout, connectionTimeout, socketTimeout, maskedLoggingHeaders, maskedLoggingBodyFields {{>partials/authEndpoint}}) ) }