From b36b9e6cf1a4dc786968cf4ec33ac58fda1e2a8b Mon Sep 17 00:00:00 2001 From: Dana AlTayeh Date: Tue, 26 Nov 2024 18:57:22 +0300 Subject: [PATCH] feat: SDK-1568 expose okhttp client as a configuration in sdk core (#857) --- .../sdk/core/client/BaseRapidClient.kt | 16 +- .../sdk/core/client/BaseXapClient.kt | 16 +- .../expediagroup/sdk/core/client/Client.kt | 148 +++++++++++------- .../sdk/core/client/ExpediaGroupClient.kt | 2 +- .../sdk/core/client/OkHttpEventListener.kt | 66 +++++--- .../core/configuration/ClientConfiguration.kt | 5 +- .../ExpediaGroupClientConfiguration.kt | 3 + .../configuration/RapidClientConfiguration.kt | 4 +- .../configuration/XapClientConfiguration.kt | 4 +- .../collector/ConfigurationCollector.kt | 2 + .../provider/ConfigurationProvider.kt | 5 + .../provider/RuntimeConfigurationProvider.kt | 4 +- .../sdk/core/constant/ConfigurationName.kt | 2 + .../ExpediaGroupClientConfigurationTest.kt | 2 + .../expediagroup-sdk/client.mustache | 2 +- 15 files changed, 192 insertions(+), 89 deletions(-) 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 c1b903440..52d20daa3 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 @@ -22,6 +22,7 @@ import com.expediagroup.sdk.core.configuration.provider.RapidConfigurationProvid import com.expediagroup.sdk.core.plugin.authentication.strategy.AuthenticationStrategy import io.ktor.client.HttpClient import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.okhttp.OkHttp /** * The integration point between the SDK Core and the product SDKs. @@ -39,7 +40,14 @@ abstract class BaseRapidClient( clientConfiguration.toProvider(), RapidConfigurationProvider ) - private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.SIGNATURE, httpClientEngine) + + private val engine: HttpClientEngine = _configurationProvider.okHttpClient?.let { + OkHttp.create { + preconfigured = it + } + } ?: httpClientEngine + + private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.SIGNATURE, engine) init { finalize() @@ -53,5 +61,9 @@ abstract class BaseRapidClient( /** A [BaseRapidClient] builder. */ @Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients. - abstract class Builder> : Client.Builder() + abstract class Builder> : HttpConfigurableBuilder() + + /** A [BaseRapidClient] builder with ability to pass a custom okhttp client. */ + @Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients. + abstract class BuilderWithHttpClient> : Client.BuilderWithHttpClient() } diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseXapClient.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseXapClient.kt index b3f550c53..19ef01d16 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseXapClient.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/client/BaseXapClient.kt @@ -22,6 +22,7 @@ import com.expediagroup.sdk.core.configuration.provider.XapConfigurationProvider import com.expediagroup.sdk.core.plugin.authentication.strategy.AuthenticationStrategy import io.ktor.client.HttpClient import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.okhttp.OkHttp /** * The integration point between the SDK Core and the product SDKs. @@ -39,7 +40,14 @@ abstract class BaseXapClient( clientConfiguration.toProvider(), XapConfigurationProvider ) - private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.BASIC, httpClientEngine) + + private val engine: HttpClientEngine = _configurationProvider.okHttpClient?.let { + OkHttp.create { + preconfigured = it + } + } ?: httpClientEngine + + private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.BASIC, engine) init { finalize() @@ -53,5 +61,9 @@ abstract class BaseXapClient( /** A [BaseXapClient] builder. */ @Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients. - abstract class Builder> : Client.Builder() + abstract class Builder> : HttpConfigurableBuilder() + + /** A [BaseXapClient] builder with ability to pass a custom okhttp client. */ + @Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients. + abstract class BuilderWithHttpClient> : Client.BuilderWithHttpClient() } 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 11ed5ea8d..6487953bc 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 @@ -51,6 +51,7 @@ import io.ktor.client.engine.okhttp.OkHttp import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.request import okhttp3.Dispatcher +import okhttp3.OkHttpClient // Create a Dispatcher with limits val dispatcher = Dispatcher().apply { @@ -61,7 +62,7 @@ val dispatcher = Dispatcher().apply { val DEFAULT_HTTP_CLIENT_ENGINE: HttpClientEngine = OkHttp.create { config { - eventListener(OkHttpEventListener) + eventListenerFactory(OkHttpEventListener.FACTORY) dispatcher(dispatcher) } } @@ -147,7 +148,7 @@ abstract class Client( suspend fun performGet(url: String): HttpResponse = httpHandler.performGet(httpClient, url) /** - * A [Client] builder. + * A [Client] base builder. */ abstract class Builder> { /** Sets the API key to use for authentication. */ @@ -159,33 +160,6 @@ abstract class Client( /** 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 @@ -223,6 +197,75 @@ abstract class Client( return self() } + /** + * Sets tne headers to be masked in logging. + * + * @param headers the headers to be masked in logging. + * @return The [Builder] instance. + */ + fun maskedLoggingHeaders(vararg headers: String): SELF { + this.maskedLoggingHeaders = headers.toSet() + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_HEADERS, headers.joinToString())) + return self() + } + + /** + * Sets tne body fields to be masked in logging. + * + * @param fields the body fields to be masked in logging. + * @return The [Builder] instance. + */ + fun maskedLoggingBodyFields(vararg fields: String): SELF { + this.maskedLoggingBodyFields = fields.toSet() + log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_BODY_FIELDS, fields.joinToString())) + return self() + } + + /** Create a [Client] object. */ + abstract fun build(): Client + + @Suppress("UNCHECKED_CAST") // This is safe because of the type parameter + protected open fun self(): SELF = this as SELF + } + + + /** + * A builder class for configuring HTTP-related settings for a [Client]. + * + * This builder class extends the base [Client.Builder] class and provides additional methods + * for configuring HTTP-specific settings such as request timeout, connection timeout, and socket timeout. + * + * @param The type of the builder itself, used for method chaining. + */ + abstract class HttpConfigurableBuilder> : Builder() { + + /** + * 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 the request timeout in milliseconds. * Request timeout is the time period from the start of the request to the completion of the response. @@ -265,35 +308,30 @@ abstract class Client( return self() } - /** - * Sets tne headers to be masked in logging. - * - * @param headers the headers to be masked in logging. - * @return The [Builder] instance. - */ - fun maskedLoggingHeaders(vararg headers: String): SELF { - this.maskedLoggingHeaders = headers.toSet() - log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_HEADERS, headers.joinToString())) - return self() - } + /** Create a [Client] object. */ + abstract override fun build(): Client + } - /** - * Sets tne body fields to be masked in logging. - * - * @param fields the body fields to be masked in logging. - * @return The [Builder] instance. - */ - fun maskedLoggingBodyFields(vararg fields: String): SELF { - this.maskedLoggingBodyFields = fields.toSet() - log.info(LoggingMessageProvider.getRuntimeConfigurationProviderMessage(ConfigurationName.MASKED_LOGGING_BODY_FIELDS, fields.joinToString())) - return self() - } - /** Create a [Client] object. */ - abstract fun build(): Client + /** + * A builder class for configuring HTTP-related settings for a [Client] with the ability to pass a custom [OkHttpClient]. + * + * This builder class extends the base [Client.Builder] class and provides additional methods + * for setting a configured okhttp client. + * + * @param The type of the builder itself, used for method chaining. + */ + abstract class BuilderWithHttpClient> : Builder() { + protected var okHttpClient: OkHttpClient? = null - @Suppress("UNCHECKED_CAST") // This is safe because of the type parameter - protected open fun self(): SELF = this as SELF + @Suppress("UNCHECKED_CAST") + override fun self(): SELF = this as SELF + + /** Sets the [OkHttpClient] to use for the [Client]. */ + fun okHttpClient(okHttpClient: OkHttpClient): SELF { + this.okHttpClient = okHttpClient + 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 cf28f895d..b47306deb 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 @@ -53,7 +53,7 @@ abstract class ExpediaGroupClient( /** An [ExpediaGroupClient] builder. */ @Suppress("unused") // This is used by the generated SDK clients. - abstract class Builder> : Client.Builder() { + abstract class Builder> : HttpConfigurableBuilder() { /** Sets the API auth endpoint to use for requests. */ protected var authEndpoint: String? = null diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/client/OkHttpEventListener.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/client/OkHttpEventListener.kt index 25dbd741a..3374e9347 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/client/OkHttpEventListener.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/client/OkHttpEventListener.kt @@ -19,28 +19,46 @@ import com.expediagroup.sdk.core.constant.HeaderKey import com.expediagroup.sdk.core.plugin.logging.ExpediaGroupLoggerFactory import okhttp3.Call import okhttp3.Connection -import okhttp3.EventListener import okhttp3.Handshake import okhttp3.Protocol import okhttp3.Request import okhttp3.Response +import okhttp3.EventListener import java.io.IOException import java.net.InetSocketAddress import java.net.Proxy +import java.util.concurrent.atomic.AtomicReference + +/** + * An `EventListener` implementation for OkHttp that logs various events during the lifecycle of an HTTP call. + * + * This listener logs events such as call start, call end, connection start, connection end, request headers start, + * request headers end, request body start, request body end, response headers start, response headers end, + * response body start, response body end, and failures. + * + * @property transactionId A reference to the unique transaction ID associated with the HTTP call. + */ +class OkHttpEventListener private constructor(private val transactionId: AtomicReference) : EventListener() { -object OkHttpEventListener : EventListener() { private val log = ExpediaGroupLoggerFactory.getLogger(this::class.java) - fun Call.getTransactionId() = request().headers[HeaderKey.TRANSACTION_ID] + companion object { + val FACTORY: Factory = + Factory { call -> + val transactionIdHeader = call.request().header(HeaderKey.TRANSACTION_ID) + val transactionId = AtomicReference(transactionIdHeader.toString()) + OkHttpEventListener(transactionId) + } + } override fun callStart(call: Call) { super.callStart(call) - log.debug("Call start for transaction-id: [${call.getTransactionId()}]") + log.debug("Call start for transaction-id: [{}]", transactionId.get()) } override fun callEnd(call: Call) { super.callEnd(call) - log.debug("Call end for transaction-id: [${call.getTransactionId()}]") + log.debug("Call end for transaction-id: [{}]", transactionId.get()) } override fun callFailed( @@ -48,12 +66,12 @@ object OkHttpEventListener : EventListener() { ioe: IOException ) { super.callFailed(call, ioe) - log.debug("Call failed for transaction-id: [${call.getTransactionId()}] with exception message: ${ioe.message}") + log.debug("Call failed for transaction-id: [{}] with exception message: {}", transactionId.get(), ioe.message) } override fun canceled(call: Call) { super.canceled(call) - log.debug("Call canceled for transaction-id: [${call.getTransactionId()}]") + log.debug("Call canceled for transaction-id: [{}]", transactionId.get()) } override fun connectStart( @@ -62,7 +80,7 @@ object OkHttpEventListener : EventListener() { proxy: Proxy ) { super.connectStart(call, inetSocketAddress, proxy) - log.debug("Connect start for transaction-id: [${call.getTransactionId()}]") + log.debug("Connect start for transaction-id: [{}]", transactionId.get()) } override fun connectEnd( @@ -72,7 +90,7 @@ object OkHttpEventListener : EventListener() { protocol: Protocol? ) { super.connectEnd(call, inetSocketAddress, proxy, protocol) - log.debug("Connect end for transaction-id: [${call.getTransactionId()}]") + log.debug("Connect end for transaction-id: [{}]", transactionId.get()) } override fun connectFailed( @@ -83,7 +101,7 @@ object OkHttpEventListener : EventListener() { ioe: IOException ) { super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe) - log.debug("Connect failed for transaction-id: [${call.getTransactionId()}] with exception message: ${ioe.message}") + log.debug("Connect failed for transaction-id: [{}] with exception message: {}", transactionId.get(), ioe.message) } override fun connectionAcquired( @@ -91,7 +109,7 @@ object OkHttpEventListener : EventListener() { connection: Connection ) { super.connectionAcquired(call, connection) - log.debug("Connection acquired for transaction-id: [${call.getTransactionId()}]") + log.debug("Connection acquired for transaction-id: [{}]", transactionId.get()) } override fun connectionReleased( @@ -99,12 +117,12 @@ object OkHttpEventListener : EventListener() { connection: Connection ) { super.connectionReleased(call, connection) - log.debug("Connection released for transaction-id: [${call.getTransactionId()}]") + log.debug("Connection released for transaction-id: [{}]", transactionId.get()) } override fun secureConnectStart(call: Call) { super.secureConnectStart(call) - log.debug("Secure connect start for transaction-id: [${call.getTransactionId()}]") + log.debug("Secure connect start for transaction-id: [{}]", transactionId.get()) } override fun secureConnectEnd( @@ -112,12 +130,12 @@ object OkHttpEventListener : EventListener() { handshake: Handshake? ) { super.secureConnectEnd(call, handshake) - log.debug("Secure connect end for transaction-id: [${call.getTransactionId()}]") + log.debug("Secure connect end for transaction-id: [{}]", transactionId.get()) } override fun requestHeadersStart(call: Call) { super.requestHeadersStart(call) - log.debug("Sending request headers start for transaction-id: [${call.getTransactionId()}]") + log.debug("Sending request headers start for transaction-id: [{}]", transactionId.get()) } override fun requestHeadersEnd( @@ -125,12 +143,12 @@ object OkHttpEventListener : EventListener() { request: Request ) { super.requestHeadersEnd(call, request) - log.debug("Sending request headers end for transaction-id: [${call.getTransactionId()}]") + log.debug("Sending request headers end for transaction-id: [{}]", transactionId.get()) } override fun requestBodyStart(call: Call) { super.requestBodyStart(call) - log.debug("Sending request body start for transaction-id: [${call.getTransactionId()}]") + log.debug("Sending request body start for transaction-id: [{}]", transactionId.get()) } override fun requestBodyEnd( @@ -138,7 +156,7 @@ object OkHttpEventListener : EventListener() { byteCount: Long ) { super.requestBodyEnd(call, byteCount) - log.debug("Sending request body end for transaction-id: [${call.getTransactionId()}] with byte count: $byteCount") + log.debug("Sending request body end for transaction-id: [{}] with byte count: {}", transactionId.get(), byteCount) } override fun requestFailed( @@ -146,12 +164,12 @@ object OkHttpEventListener : EventListener() { ioe: IOException ) { super.requestFailed(call, ioe) - log.debug("Request failed for transaction-id: [${call.getTransactionId()}] with exception message: ${ioe.message}") + log.debug("Request failed for transaction-id: [{}] with exception message: {}", transactionId.get(), ioe.message) } override fun responseHeadersStart(call: Call) { super.responseHeadersStart(call) - log.debug("Receiving response headers start for transaction-id: [${call.getTransactionId()}]") + log.debug("Receiving response headers start for transaction-id: [{}]", transactionId.get()) } override fun responseHeadersEnd( @@ -159,12 +177,12 @@ object OkHttpEventListener : EventListener() { response: Response ) { super.responseHeadersEnd(call, response) - log.debug("Receiving response headers end for transaction-id: [${call.getTransactionId()}]") + log.debug("Receiving response headers end for transaction-id: [{}]", transactionId.get()) } override fun responseBodyStart(call: Call) { super.responseBodyStart(call) - log.debug("Receiving response body start for transaction-id: [${call.getTransactionId()}]") + log.debug("Receiving response body start for transaction-id: [{}]", transactionId.get()) } override fun responseBodyEnd( @@ -172,7 +190,7 @@ object OkHttpEventListener : EventListener() { byteCount: Long ) { super.responseBodyEnd(call, byteCount) - log.debug("Receiving response body end for transaction-id: [${call.getTransactionId()}] with byte count: $byteCount") + log.debug("Receiving response body end for transaction-id: [{}] with byte count: {}", transactionId.get(), byteCount) } override fun responseFailed( @@ -180,6 +198,6 @@ object OkHttpEventListener : EventListener() { ioe: IOException ) { super.responseFailed(call, ioe) - log.debug("Receiving response failed for transaction-id: [${call.getTransactionId()}] with exception message: ${ioe.message}") + log.debug("Receiving response failed for transaction-id: [{}] with exception message: {}", transactionId.get(), ioe.message) } } 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 d8dfdedd9..557db5ed6 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 @@ -16,6 +16,7 @@ package com.expediagroup.sdk.core.configuration import com.expediagroup.sdk.core.configuration.provider.RuntimeConfigurationProvider +import okhttp3.OkHttpClient interface ClientConfiguration { val key: String? @@ -26,6 +27,7 @@ interface ClientConfiguration { val socketTimeout: Long? val maskedLoggingHeaders: Set? val maskedLoggingBodyFields: Set? + val okHttpClient: OkHttpClient? /** Build a [RuntimeConfigurationProvider] from a [ClientConfiguration]. */ fun toProvider(): RuntimeConfigurationProvider = @@ -37,6 +39,7 @@ interface ClientConfiguration { connectionTimeout = connectionTimeout, socketTimeout = socketTimeout, maskedLoggingHeaders = maskedLoggingHeaders, - maskedLoggingBodyFields = maskedLoggingBodyFields + maskedLoggingBodyFields = maskedLoggingBodyFields, + okHttpClient = okHttpClient ) } 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 e5289d9e9..917604d76 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 @@ -17,6 +17,7 @@ package com.expediagroup.sdk.core.configuration import com.expediagroup.sdk.core.client.ExpediaGroupClient import com.expediagroup.sdk.core.configuration.provider.RuntimeConfigurationProvider +import okhttp3.OkHttpClient /** * Configuration for the [ExpediaGroupClient]. @@ -30,6 +31,7 @@ import com.expediagroup.sdk.core.configuration.provider.RuntimeConfigurationProv * @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. + * @property okHttpClient The okhttp client to be used by the sdk. */ data class ExpediaGroupClientConfiguration( override val key: String? = null, @@ -40,6 +42,7 @@ data class ExpediaGroupClientConfiguration( override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, override val maskedLoggingBodyFields: Set? = null, + override val okHttpClient: OkHttpClient? = null, val authEndpoint: String? = null ) : ClientConfiguration { /** Build a [RuntimeConfigurationProvider] from an [ExpediaGroupClientConfiguration]. */ 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 cac3637de..48a1cef94 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 @@ -16,6 +16,7 @@ package com.expediagroup.sdk.core.configuration import com.expediagroup.sdk.core.client.BaseRapidClient +import okhttp3.OkHttpClient /** * Configuration for the [BaseRapidClient]. @@ -37,5 +38,6 @@ data class RapidClientConfiguration( override val connectionTimeout: Long? = null, override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, - override val maskedLoggingBodyFields: Set? = null + override val maskedLoggingBodyFields: Set? = null, + override val okHttpClient: OkHttpClient? = null ) : ClientConfiguration diff --git a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/XapClientConfiguration.kt b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/XapClientConfiguration.kt index f17f9d778..ec72f80d7 100644 --- a/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/XapClientConfiguration.kt +++ b/core/src/main/kotlin/com/expediagroup/sdk/core/configuration/XapClientConfiguration.kt @@ -16,6 +16,7 @@ package com.expediagroup.sdk.core.configuration import com.expediagroup.sdk.core.client.BaseXapClient +import okhttp3.OkHttpClient /** * Configuration for the [BaseXapClient]. @@ -37,5 +38,6 @@ data class XapClientConfiguration( override val connectionTimeout: Long? = null, override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, - override val maskedLoggingBodyFields: Set? = null + override val maskedLoggingBodyFields: Set? = null, + override val okHttpClient: OkHttpClient? = 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 a83d40fbe..49b674182 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 @@ -28,6 +28,7 @@ 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 +import okhttp3.OkHttpClient /** * Configuration collector that collects configuration from all available providers. @@ -66,6 +67,7 @@ internal class ConfigurationCollector private constructor(providers: Configurati 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() + override val okHttpClient: OkHttpClient? = providers.firstWith { it.okHttpClient }?.retrieve() private fun ProvidedConfiguration.log(configurationName: String) { log.info(LoggingMessageProvider.getChosenProviderMessage(configurationName, providerName)) 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 ac7f7ea43..0a14edd19 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 @@ -16,6 +16,7 @@ package com.expediagroup.sdk.core.configuration.provider import com.expediagroup.sdk.core.constant.Constant +import okhttp3.OkHttpClient /** * A configuration provider that can be used to provide configuration values. @@ -55,4 +56,8 @@ interface ConfigurationProvider { /** The body fields to be masked in logging.*/ val maskedLoggingBodyFields: Set? get() = setOf() + + /** The okhttp client to be used by the sdk.*/ + val okHttpClient: OkHttpClient? + get() = null } 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 fd72dc58e..d6e607e09 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 @@ -16,6 +16,7 @@ package com.expediagroup.sdk.core.configuration.provider import com.expediagroup.sdk.core.constant.ConfigurationName.RUNTIME_CONFIGURATION_PROVIDER +import okhttp3.OkHttpClient /** * A runtime-built configuration provider. @@ -41,5 +42,6 @@ data class RuntimeConfigurationProvider( override val connectionTimeout: Long? = null, override val socketTimeout: Long? = null, override val maskedLoggingHeaders: Set? = null, - override val maskedLoggingBodyFields: Set? = null + override val maskedLoggingBodyFields: Set? = null, + override val okHttpClient: OkHttpClient? = 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 0004086b7..0d9b9a955 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 @@ -37,4 +37,6 @@ internal object ConfigurationName { const val RUNTIME_CONFIGURATION_PROVIDER = "runtime configuration" const val CONFIGURATION_COLLECTOR = "configuration collector" + + const val OKHTTP_CLIENT = "okhttp client" } 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 3310560e8..a01f7d5bb 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 @@ -32,6 +32,7 @@ class ExpediaGroupClientConfigurationTest { assertNull(it.socketTimeout) assertNull(it.maskedLoggingHeaders) assertNull(it.maskedLoggingBodyFields) + assertNull(it.okHttpClient) } } @@ -72,6 +73,7 @@ class ExpediaGroupClientConfigurationTest { assertNull(it.socketTimeout) assertNull(it.maskedLoggingHeaders) assertNull(it.maskedLoggingBodyFields) + assertNull(it.okHttpClient) } } diff --git a/generator/openapi/src/main/resources/templates/expediagroup-sdk/client.mustache b/generator/openapi/src/main/resources/templates/expediagroup-sdk/client.mustache index 88b5a95e5..5ddbbc8fc 100644 --- a/generator/openapi/src/main/resources/templates/expediagroup-sdk/client.mustache +++ b/generator/openapi/src/main/resources/templates/expediagroup-sdk/client.mustache @@ -22,7 +22,7 @@ import kotlinx.coroutines.runBlocking class {{clientClassname}}Client private constructor(clientConfiguration: ExpediaGroupClientConfiguration) : ExpediaGroupClient("{{namespace}}", clientConfiguration) { class Builder : ExpediaGroupClient.Builder() { override fun build() = {{clientClassname}}Client( - ExpediaGroupClientConfiguration(key, secret, endpoint, requestTimeout, connectionTimeout, socketTimeout, maskedLoggingHeaders, maskedLoggingBodyFields, authEndpoint) + ExpediaGroupClientConfiguration(key, secret, endpoint, requestTimeout, connectionTimeout, socketTimeout, maskedLoggingHeaders, maskedLoggingBodyFields, null, authEndpoint) ) }