Skip to content

Commit

Permalink
feat: SDK-1568 expose okhttp client as a configuration in sdk core (#857
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dtayeh authored Nov 26, 2024
1 parent 4176782 commit b36b9e6
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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()
Expand All @@ -53,5 +61,9 @@ abstract class BaseRapidClient(

/** A [BaseRapidClient] builder. */
@Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients.
abstract class Builder<SELF : Builder<SELF>> : Client.Builder<SELF>()
abstract class Builder<SELF : Builder<SELF>> : HttpConfigurableBuilder<SELF>()

/** 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<SELF : Client.BuilderWithHttpClient<SELF>> : Client.BuilderWithHttpClient<SELF>()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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()
Expand All @@ -53,5 +61,9 @@ abstract class BaseXapClient(

/** A [BaseXapClient] builder. */
@Suppress("unused", "UnnecessaryAbstractClass") // This is used by the generated SDK clients.
abstract class Builder<SELF : Builder<SELF>> : Client.Builder<SELF>()
abstract class Builder<SELF : Builder<SELF>> : HttpConfigurableBuilder<SELF>()

/** 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<SELF : Client.BuilderWithHttpClient<SELF>> : Client.BuilderWithHttpClient<SELF>()
}
148 changes: 93 additions & 55 deletions core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -61,7 +62,7 @@ val dispatcher = Dispatcher().apply {
val DEFAULT_HTTP_CLIENT_ENGINE: HttpClientEngine =
OkHttp.create {
config {
eventListener(OkHttpEventListener)
eventListenerFactory(OkHttpEventListener.FACTORY)
dispatcher(dispatcher)
}
}
Expand Down Expand Up @@ -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<SELF : Builder<SELF>> {
/** Sets the API key to use for authentication. */
Expand All @@ -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<String>? = null

Expand Down Expand Up @@ -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 <SELF> The type of the builder itself, used for method chaining.
*/
abstract class HttpConfigurableBuilder<SELF : Builder<SELF>> : Builder<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.
*/
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.
Expand Down Expand Up @@ -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 <SELF> The type of the builder itself, used for method chaining.
*/
abstract class BuilderWithHttpClient<SELF : Builder<SELF>> : Builder<SELF>() {
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()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ abstract class ExpediaGroupClient(

/** An [ExpediaGroupClient] builder. */
@Suppress("unused") // This is used by the generated SDK clients.
abstract class Builder<SELF : Builder<SELF>> : Client.Builder<SELF>() {
abstract class Builder<SELF : Builder<SELF>> : HttpConfigurableBuilder<SELF>() {
/** Sets the API auth endpoint to use for requests. */
protected var authEndpoint: String? = null

Expand Down
Loading

0 comments on commit b36b9e6

Please sign in to comment.