Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SDK-1568 expose okhttp client as a configuration in sdk core #857

Merged
merged 6 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ 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
import okhttp3.OkHttpClient

/**
* The integration point between the SDK Core and the product SDKs.
Expand All @@ -39,7 +41,14 @@ abstract class BaseRapidClient(
clientConfiguration.toProvider(),
RapidConfigurationProvider
)
private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.SIGNATURE, httpClientEngine)

private val engine: HttpClientEngine = clientConfiguration.okHttpClient?.let {
OkHttp.create {
preconfigured = it
}
} ?: httpClientEngine

private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.SIGNATURE, engine)

init {
finalize()
Expand All @@ -53,5 +62,21 @@ 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.Builder<SELF>> : Client.Builder<SELF>() {
protected var okHttpClient: OkHttpClient? = null

@Suppress("UNCHECKED_CAST")
override fun self(): SELF = this as SELF

/** Sets the [OkHttpClient] to use for the [BaseRapidClient]. */
fun okHttpClient(okHttpClient: OkHttpClient): SELF {
this.okHttpClient = okHttpClient
return self()
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ 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
import okhttp3.OkHttpClient

/**
* The integration point between the SDK Core and the product SDKs.
Expand All @@ -39,7 +41,14 @@ abstract class BaseXapClient(
clientConfiguration.toProvider(),
XapConfigurationProvider
)
private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.BASIC, httpClientEngine)

private val engine: HttpClientEngine = clientConfiguration.okHttpClient?.let {
OkHttp.create {
preconfigured = it
}
} ?: httpClientEngine

private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.BASIC, engine)

init {
finalize()
Expand All @@ -53,5 +62,21 @@ 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.Builder<SELF>> : Client.Builder<SELF>() {
protected var okHttpClient: OkHttpClient? = null

@Suppress("UNCHECKED_CAST")
override fun self(): SELF = this as SELF

/** Sets the [OkHttpClient] to use for the [BaseXapClient]. */
fun okHttpClient(okHttpClient: OkHttpClient): SELF {
this.okHttpClient = okHttpClient
return self()
}

}
}
131 changes: 75 additions & 56 deletions core/src/main/kotlin/com/expediagroup/sdk/core/client/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,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 +147,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 +159,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 +196,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,37 +307,14 @@ 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
abstract override fun build(): Client

@Suppress("UNCHECKED_CAST") // This is safe because of the type parameter
protected open fun self(): SELF = this as SELF
}

}

/** Executes the hooks for the client. */
fun <T : Client> T.finalize() = Hooks.execute(this)


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
Loading