summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukasz Rajewski <lukasz.rajewski@t-mobile.pl>2022-08-18 21:50:31 +0200
committerLukasz Rajewski <lukasz.rajewski@t-mobile.pl>2022-08-24 14:48:20 +0000
commit9ab2a91f585864bf18fef788adeaf61f4f450b39 (patch)
tree295613f89d73e18a888e8ffd5c68be65911a7b59
parente1db2469a8e42d591bd905e588975be0f2a8861e (diff)
Refactor rest clients and support timeouts
- Refactored rest clients to remove redundant code - Timeouts added to the configuration of rest clients Issue-ID: CCSDK-3716 Signed-off-by: Lukasz Rajewski <lukasz.rajewski@t-mobile.pl> Change-Id: I706b8efd8447570455b8b65bd5b1a22da474f62b
-rw-r--r--ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/K8sAbstractRestClientService.kt52
-rw-r--r--ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt11
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt3
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt330
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt24
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt306
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt21
-rw-r--r--ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt12
8 files changed, 396 insertions, 363 deletions
diff --git a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/K8sAbstractRestClientService.kt b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/K8sAbstractRestClientService.kt
index 14f14f61b..b9c45e423 100644
--- a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/K8sAbstractRestClientService.kt
+++ b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/K8sAbstractRestClientService.kt
@@ -19,23 +19,20 @@
package org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s
-import org.apache.http.message.BasicHeader
import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
-import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
-import org.springframework.http.HttpHeaders.ACCEPT
-import org.springframework.http.HttpHeaders.AUTHORIZATION
-import org.springframework.http.HttpHeaders.CONTENT_TYPE
-import org.springframework.http.MediaType.APPLICATION_JSON_VALUE
-import java.nio.charset.Charset
-import java.util.Base64
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BasicAuthRestClientService
abstract class K8sAbstractRestClientService(
private val k8sConfiguration: K8sConnectionPluginConfiguration
-) : BlueprintWebClientService {
+) : BasicAuthRestClientService(BasicAuthRestClientProperties()) {
protected val baseUrl: String = k8sConfiguration.getProperties().url
private var restClientProperties: BasicAuthRestClientProperties? = null
+ override fun getRestClientProperties(): BasicAuthRestClientProperties {
+ return getBasicAuthRestClientProperties()
+ }
+
private fun getBasicAuthRestClientProperties(): BasicAuthRestClientProperties {
return if (restClientProperties != null)
restClientProperties!!
@@ -55,45 +52,8 @@ abstract class K8sAbstractRestClientService(
mapOfHeaders["Accept"] = "application/json"
mapOfHeaders["Content-Type"] = "application/json"
mapOfHeaders["cache-control"] = " no-cache"
- mapOfHeaders["Accept"] = "application/json"
return mapOfHeaders
}
- private fun setBasicAuth(username: String, password: String): String {
- val credentialsString = "$username:$password"
- return Base64.getEncoder().encodeToString(credentialsString.toByteArray(Charset.defaultCharset()))
- }
-
- override fun defaultHeaders(): Map<String, String> {
- val encodedCredentials = setBasicAuth(
- getBasicAuthRestClientProperties().username,
- getBasicAuthRestClientProperties().password
- )
- return mapOf(
- CONTENT_TYPE to APPLICATION_JSON_VALUE,
- ACCEPT to APPLICATION_JSON_VALUE,
- AUTHORIZATION to "Basic $encodedCredentials"
- )
- }
-
- override fun host(uri: String): String {
- return getBasicAuthRestClientProperties().url + uri
- }
-
- override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
- val customHeaders: MutableMap<String, String> = headers.toMutableMap()
- // inject additionalHeaders
- customHeaders.putAll(verifyAdditionalHeaders(getBasicAuthRestClientProperties()))
-
- if (!headers.containsKey(AUTHORIZATION)) {
- val encodedCredentials = setBasicAuth(
- getBasicAuthRestClientProperties().username,
- getBasicAuthRestClientProperties().password
- )
- customHeaders[AUTHORIZATION] = "Basic $encodedCredentials"
- }
- return super.convertToBasicHeaders(customHeaders)
- }
-
abstract fun apiUrl(): String
}
diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt
index 86a9ed056..ba273e179 100644
--- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt
+++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt
@@ -21,6 +21,7 @@ import org.mockserver.model.Header
import org.mockserver.model.HttpRequest.request
import org.mockserver.model.HttpResponse.response
import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BaseBlueprintWebClientService
import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
@@ -28,7 +29,7 @@ import java.nio.charset.Charset
import java.util.Base64
class MockBlueprintWebClientService(private var restClientProperties: RestClientProperties) :
- BlueprintWebClientService {
+ BaseBlueprintWebClientService<RestClientProperties>() {
private var mockServer: ClientAndServer
private var port: String = if (restClientProperties.url.split(":")[2].isEmpty()) "8080"
@@ -52,6 +53,10 @@ class MockBlueprintWebClientService(private var restClientProperties: RestClient
)
}
+ override fun getRestClientProperties(): RestClientProperties {
+ return restClientProperties
+ }
+
override fun defaultHeaders(): Map<String, String> {
val encodedCredentials = this.setBasicAuth("admin", "aaiTest")
return mapOf(
@@ -61,10 +66,6 @@ class MockBlueprintWebClientService(private var restClientProperties: RestClient
)
}
- override fun host(uri: String): String {
- return restClientProperties.url + uri
- }
-
fun tearDown() {
mockServer.close()
}
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt
index 01011cc83..b0282c40f 100644
--- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/BluePrintRestLibData.kt
@@ -22,6 +22,9 @@ open class RestClientProperties {
lateinit var type: String
lateinit var url: String
+ var connectTimeout: Int = 0
+ var socketTimeout: Int = 0
+ var connectionRequestTimeout: Int = 0
var additionalHeaders: Map<String, String>? = null
}
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt
new file mode 100644
index 000000000..bc1dc4e09
--- /dev/null
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BaseBlueprintWebClientService.kt
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2017-2019 AT&T, Bell Canada, Nordix Foundation
+ * Modifications Copyright © 2018-2019 IBM.
+ * Modifications Copyright © 2019 Huawei.
+ * Modifications Copyright © 2022 Deutsche Telekom AG.
+ *
+ * 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 org.onap.ccsdk.cds.blueprintsprocessor.rest.service
+
+import com.fasterxml.jackson.databind.JsonNode
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.apache.commons.io.IOUtils
+import org.apache.http.client.ClientProtocolException
+import org.apache.http.client.config.RequestConfig
+import org.apache.http.client.methods.HttpDelete
+import org.apache.http.client.methods.HttpGet
+import org.apache.http.client.methods.HttpPatch
+import org.apache.http.client.methods.HttpPost
+import org.apache.http.client.methods.HttpPut
+import org.apache.http.client.methods.HttpUriRequest
+import org.apache.http.entity.StringEntity
+import org.apache.http.impl.client.CloseableHttpClient
+import org.apache.http.impl.client.HttpClients
+import org.apache.http.message.BasicHeader
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestLibConstants
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpMethod
+import java.io.IOException
+import java.io.InputStream
+import java.net.URI
+import java.nio.charset.Charset
+
+abstract class BaseBlueprintWebClientService<out E : RestClientProperties> : BlueprintWebClientService {
+
+ open fun host(uri: String): String {
+ val uri: URI = URI.create(getRestClientProperties().url + uri)
+ return uri.resolve(uri).toString()
+ }
+
+ abstract fun getRestClientProperties(): E
+
+ open fun getRequestConfig(): RequestConfig {
+ val requestConfigBuilder = RequestConfig.custom()
+ if (getRestClientProperties().connectionRequestTimeout > 0)
+ requestConfigBuilder.setConnectionRequestTimeout(getRestClientProperties().connectionRequestTimeout)
+ if (getRestClientProperties().connectTimeout > 0)
+ requestConfigBuilder.setConnectTimeout(getRestClientProperties().connectTimeout)
+ if (getRestClientProperties().socketTimeout > 0)
+ requestConfigBuilder.setSocketTimeout(getRestClientProperties().socketTimeout)
+ return requestConfigBuilder.build()
+ }
+
+ open fun httpClient(): CloseableHttpClient {
+ return HttpClients.custom()
+ .addInterceptorFirst(WebClientUtils.logRequest())
+ .addInterceptorLast(WebClientUtils.logResponse())
+ .setDefaultRequestConfig(getRequestConfig())
+ .build()
+ }
+
+ override fun exchangeResource(methodType: String, path: String, request: String): BlueprintWebClientService.WebClientResponse<String> {
+ return this.exchangeResource(methodType, path, request, defaultHeaders())
+ }
+
+ override fun exchangeResource(
+ methodType: String,
+ path: String,
+ request: String,
+ headers: Map<String, String>
+ ): BlueprintWebClientService.WebClientResponse<String> {
+ /**
+ * TODO: Basic headers in the implementations of this client do not get added
+ * in blocking version, whereas in NB version defaultHeaders get added.
+ * the difference is in convertToBasicHeaders vs basicHeaders
+ */
+ val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(headers)
+ return when (HttpMethod.resolve(methodType)) {
+ HttpMethod.DELETE -> delete(path, convertedHeaders, String::class.java)
+ HttpMethod.GET -> get(path, convertedHeaders, String::class.java)
+ HttpMethod.POST -> post(path, request, convertedHeaders, String::class.java)
+ HttpMethod.PUT -> put(path, request, convertedHeaders, String::class.java)
+ HttpMethod.PATCH -> patch(path, request, convertedHeaders, String::class.java)
+ else -> throw BluePrintProcessorException(
+ "Unsupported methodType($methodType) attempted on path($path)"
+ )
+ }
+ }
+
+ // TODO: convert to multi-map
+ override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
+ return headers.map { BasicHeader(it.key, it.value) }.toTypedArray()
+ }
+
+ open fun <T> delete(path: String, headers: Array<BasicHeader>, responseType: Class<T>): BlueprintWebClientService.WebClientResponse<T> {
+ val httpDelete = HttpDelete(host(path))
+ RestLoggerService.httpInvoking(headers)
+ httpDelete.setHeaders(headers)
+ return performCallAndExtractTypedWebClientResponse(httpDelete, responseType)
+ }
+
+ open fun <T> get(path: String, headers: Array<BasicHeader>, responseType: Class<T>): BlueprintWebClientService.WebClientResponse<T> {
+ val httpGet = HttpGet(host(path))
+ RestLoggerService.httpInvoking(headers)
+ httpGet.setHeaders(headers)
+ return performCallAndExtractTypedWebClientResponse(httpGet, responseType)
+ }
+
+ open fun <T> post(path: String, request: Any, headers: Array<BasicHeader>, responseType: Class<T>): BlueprintWebClientService.WebClientResponse<T> {
+ val httpPost = HttpPost(host(path))
+ val entity = StringEntity(strRequest(request))
+ httpPost.entity = entity
+ RestLoggerService.httpInvoking(headers)
+ httpPost.setHeaders(headers)
+ return performCallAndExtractTypedWebClientResponse(httpPost, responseType)
+ }
+
+ open fun <T> put(path: String, request: Any, headers: Array<BasicHeader>, responseType: Class<T>): BlueprintWebClientService.WebClientResponse<T> {
+ val httpPut = HttpPut(host(path))
+ val entity = StringEntity(strRequest(request))
+ httpPut.entity = entity
+ RestLoggerService.httpInvoking(headers)
+ httpPut.setHeaders(headers)
+ return performCallAndExtractTypedWebClientResponse(httpPut, responseType)
+ }
+
+ open fun <T> patch(path: String, request: Any, headers: Array<BasicHeader>, responseType: Class<T>): BlueprintWebClientService.WebClientResponse<T> {
+ val httpPatch = HttpPatch(host(path))
+ val entity = StringEntity(strRequest(request))
+ httpPatch.entity = entity
+ RestLoggerService.httpInvoking(headers)
+ httpPatch.setHeaders(headers)
+ return performCallAndExtractTypedWebClientResponse(httpPatch, responseType)
+ }
+
+ /**
+ * Perform the HTTP call and return HTTP status code and body.
+ * @param httpUriRequest {@link HttpUriRequest} object
+ * @return {@link WebClientResponse} object
+ * http client may throw IOException and ClientProtocolException on error
+ */
+
+ @Throws(IOException::class, ClientProtocolException::class)
+ protected fun <T> performCallAndExtractTypedWebClientResponse(
+ httpUriRequest: HttpUriRequest,
+ responseType: Class<T>
+ ):
+ BlueprintWebClientService.WebClientResponse<T> {
+ val httpResponse = httpClient().execute(httpUriRequest)
+ val statusCode = httpResponse.statusLine.statusCode
+ httpResponse.entity.content.use {
+ val body = getResponse(it, responseType)
+ return BlueprintWebClientService.WebClientResponse(statusCode, body)
+ }
+ }
+
+ open suspend fun getNB(path: String): BlueprintWebClientService.WebClientResponse<String> {
+ return getNB(path, null, String::class.java)
+ }
+
+ open suspend fun getNB(path: String, additionalHeaders: Array<BasicHeader>?): BlueprintWebClientService.WebClientResponse<String> {
+ return getNB(path, additionalHeaders, String::class.java)
+ }
+
+ open suspend fun <T> getNB(path: String, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>):
+ BlueprintWebClientService.WebClientResponse<T> = withContext(Dispatchers.IO) {
+ get(path, additionalHeaders!!, responseType)
+ }
+
+ open suspend fun postNB(path: String, request: Any): BlueprintWebClientService.WebClientResponse<String> {
+ return postNB(path, request, null, String::class.java)
+ }
+
+ open suspend fun postNB(path: String, request: Any, additionalHeaders: Array<BasicHeader>?): BlueprintWebClientService.WebClientResponse<String> {
+ return postNB(path, request, additionalHeaders, String::class.java)
+ }
+
+ open suspend fun <T> postNB(
+ path: String,
+ request: Any,
+ additionalHeaders: Array<BasicHeader>?,
+ responseType: Class<T>
+ ): BlueprintWebClientService.WebClientResponse<T> = withContext(Dispatchers.IO) {
+ post(path, request, additionalHeaders!!, responseType)
+ }
+
+ open suspend fun putNB(path: String, request: Any): BlueprintWebClientService.WebClientResponse<String> {
+ return putNB(path, request, null, String::class.java)
+ }
+
+ open suspend fun putNB(
+ path: String,
+ request: Any,
+ additionalHeaders: Array<BasicHeader>?
+ ): BlueprintWebClientService.WebClientResponse<String> {
+ return putNB(path, request, additionalHeaders, String::class.java)
+ }
+
+ open suspend fun <T> putNB(
+ path: String,
+ request: Any,
+ additionalHeaders: Array<BasicHeader>?,
+ responseType: Class<T>
+ ): BlueprintWebClientService.WebClientResponse<T> = withContext(Dispatchers.IO) {
+ put(path, request, additionalHeaders!!, responseType)
+ }
+
+ open suspend fun <T> deleteNB(path: String): BlueprintWebClientService.WebClientResponse<String> {
+ return deleteNB(path, null, String::class.java)
+ }
+
+ open suspend fun <T> deleteNB(path: String, additionalHeaders: Array<BasicHeader>?):
+ BlueprintWebClientService.WebClientResponse<String> {
+ return deleteNB(path, additionalHeaders, String::class.java)
+ }
+
+ open suspend fun <T> deleteNB(path: String, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>):
+ BlueprintWebClientService.WebClientResponse<T> = withContext(Dispatchers.IO) {
+ delete(path, additionalHeaders!!, responseType)
+ }
+
+ open suspend fun <T> patchNB(path: String, request: Any, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>):
+ BlueprintWebClientService.WebClientResponse<T> = withContext(Dispatchers.IO) {
+ patch(path, request, additionalHeaders!!, responseType)
+ }
+
+ override suspend fun exchangeNB(methodType: String, path: String, request: Any): BlueprintWebClientService.WebClientResponse<String> {
+ return exchangeNB(
+ methodType, path, request, hashMapOf(),
+ String::class.java
+ )
+ }
+
+ override suspend fun exchangeNB(methodType: String, path: String, request: Any, additionalHeaders: Map<String, String>?):
+ BlueprintWebClientService.WebClientResponse<String> {
+ return exchangeNB(methodType, path, request, additionalHeaders, String::class.java)
+ }
+
+ override suspend fun <T> exchangeNB(
+ methodType: String,
+ path: String,
+ request: Any,
+ additionalHeaders: Map<String, String>?,
+ responseType: Class<T>
+ ): BlueprintWebClientService.WebClientResponse<T> {
+
+ // TODO: possible inconsistency
+ // NOTE: this basic headers function is different from non-blocking
+ val convertedHeaders: Array<BasicHeader> = basicHeaders(additionalHeaders!!)
+ return when (HttpMethod.resolve(methodType)) {
+ HttpMethod.GET -> getNB(path, convertedHeaders, responseType)
+ HttpMethod.POST -> postNB(path, request, convertedHeaders, responseType)
+ HttpMethod.DELETE -> deleteNB(path, convertedHeaders, responseType)
+ HttpMethod.PUT -> putNB(path, request, convertedHeaders, responseType)
+ HttpMethod.PATCH -> patchNB(path, request, convertedHeaders, responseType)
+ else -> throw BluePrintProcessorException("Unsupported methodType($methodType)")
+ }
+ }
+
+ protected fun strRequest(request: Any): String {
+ return when (request) {
+ is String -> request.toString()
+ is JsonNode -> request.toString()
+ else -> JacksonUtils.getJson(request)
+ }
+ }
+
+ protected fun <T> getResponse(it: InputStream, responseType: Class<T>): T {
+ return if (responseType == String::class.java) {
+ IOUtils.toString(it, Charset.defaultCharset()) as T
+ } else {
+ JacksonUtils.readValue(it, responseType)!!
+ }
+ }
+
+ protected fun basicHeaders(headers: Map<String, String>?):
+ Array<BasicHeader> {
+ val basicHeaders = mutableListOf<BasicHeader>()
+ defaultHeaders().forEach { (name, value) ->
+ basicHeaders.add(BasicHeader(name, value))
+ }
+ headers?.forEach { name, value ->
+ basicHeaders.add(BasicHeader(name, value))
+ }
+ return basicHeaders.toTypedArray()
+ }
+
+ // Non Blocking Rest Implementation
+ suspend fun httpClientNB(): CloseableHttpClient {
+ return httpClient()
+ }
+
+ open fun verifyAdditionalHeaders(): Map<String, String> {
+ return verifyAdditionalHeaders(getRestClientProperties())
+ }
+
+ open fun verifyAdditionalHeaders(restClientProperties: RestClientProperties): Map<String, String> {
+ val customHeaders: MutableMap<String, String> = mutableMapOf()
+ // Extract additionalHeaders from the requestProperties and
+ // throw an error if HttpHeaders.AUTHORIZATION key (headers are case-insensitive)
+ restClientProperties.additionalHeaders?.let {
+ if (it.keys.map { k -> k.toLowerCase().trim() }.contains(HttpHeaders.AUTHORIZATION.toLowerCase())) {
+ val errMsg = "Error in definition of endpoint ${restClientProperties.url}." +
+ " User-supplied \"additionalHeaders\" cannot contain AUTHORIZATION header with" +
+ " auth-type \"${RestLibConstants.TYPE_BASIC_AUTH}\""
+ WebClientUtils.log.error(errMsg)
+ throw BluePrintProcessorException(errMsg)
+ } else {
+ customHeaders.putAll(it)
+ }
+ }
+ return customHeaders
+ }
+}
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt
index be9b849f6..943a3550d 100644
--- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt
@@ -20,21 +20,24 @@ import org.apache.http.message.BasicHeader
import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
-import java.net.URI
import java.nio.charset.Charset
import java.util.Base64
-class BasicAuthRestClientService(
+open class BasicAuthRestClientService(
private val restClientProperties:
BasicAuthRestClientProperties
) :
- BlueprintWebClientService {
+ BaseBlueprintWebClientService<BasicAuthRestClientProperties>() {
+
+ override fun getRestClientProperties(): BasicAuthRestClientProperties {
+ return restClientProperties
+ }
override fun defaultHeaders(): Map<String, String> {
val encodedCredentials = setBasicAuth(
- restClientProperties.username,
- restClientProperties.password
+ getRestClientProperties().username,
+ getRestClientProperties().password
)
return mapOf(
HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
@@ -43,21 +46,16 @@ class BasicAuthRestClientService(
)
}
- override fun host(uri: String): String {
- val uri: URI = URI.create(restClientProperties.url + uri)
- return uri.resolve(uri).toString()
- }
-
override fun convertToBasicHeaders(headers: Map<String, String>):
Array<BasicHeader> {
val customHeaders: MutableMap<String, String> = headers.toMutableMap()
// inject additionalHeaders
- customHeaders.putAll(verifyAdditionalHeaders(restClientProperties))
+ customHeaders.putAll(verifyAdditionalHeaders())
if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
val encodedCredentials = setBasicAuth(
- restClientProperties.username,
- restClientProperties.password
+ getRestClientProperties().username,
+ getRestClientProperties().password
)
customHeaders[HttpHeaders.AUTHORIZATION] =
"Basic $encodedCredentials"
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt
index 945d29850..ed52e6212 100644
--- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/BlueprintWebClientService.kt
@@ -2,6 +2,7 @@
* Copyright © 2017-2019 AT&T, Bell Canada, Nordix Foundation
* Modifications Copyright © 2018-2019 IBM.
* Modifications Copyright © 2019 Huawei.
+ * Modifications Copyright © 2022 Deutsche Telekom AG.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,240 +19,33 @@
package org.onap.ccsdk.cds.blueprintsprocessor.rest.service
-import com.fasterxml.jackson.databind.JsonNode
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import org.apache.commons.io.IOUtils
-import org.apache.http.client.ClientProtocolException
-import org.apache.http.client.methods.HttpDelete
-import org.apache.http.client.methods.HttpGet
-import org.apache.http.client.methods.HttpPatch
-import org.apache.http.client.methods.HttpPost
-import org.apache.http.client.methods.HttpPut
-import org.apache.http.client.methods.HttpUriRequest
-import org.apache.http.entity.StringEntity
-import org.apache.http.impl.client.CloseableHttpClient
-import org.apache.http.impl.client.HttpClients
import org.apache.http.message.BasicHeader
-import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties
-import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestLibConstants
-import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintRetryException
import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintIOUtils
-import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
-import org.springframework.http.HttpHeaders
-import org.springframework.http.HttpMethod
-import java.io.IOException
-import java.io.InputStream
-import java.nio.charset.Charset
interface BlueprintWebClientService {
-
fun defaultHeaders(): Map<String, String>
-
- fun host(uri: String): String
-
- fun httpClient(): CloseableHttpClient {
- return HttpClients.custom()
- .addInterceptorFirst(WebClientUtils.logRequest())
- .addInterceptorLast(WebClientUtils.logResponse())
- .build()
- }
-
- /** High performance non blocking Retry function, If execution block [block] throws BluePrintRetryException
- * exception then this will perform wait and retrigger accoring to times [times] with delay [delay]
- */
- suspend fun <T> retry(
- times: Int = 1,
- initialDelay: Long = 0,
- delay: Long = 1000,
- block: suspend (Int) -> T
- ): T {
- val exceptionBlock = { e: Exception ->
- if (e !is BluePrintRetryException) {
- throw e
- }
- }
- return BluePrintIOUtils.retry(times, initialDelay, delay, block, exceptionBlock)
- }
-
- fun exchangeResource(methodType: String, path: String, request: String): WebClientResponse<String> {
- return this.exchangeResource(methodType, path, request, defaultHeaders())
- }
+ fun convertToBasicHeaders(
+ mergedDefaultAndSuppliedHeaders: Map<String, String>
+ ): Array<BasicHeader>
fun exchangeResource(
methodType: String,
path: String,
request: String,
headers: Map<String, String>
- ): WebClientResponse<String> {
- /**
- * TODO: Basic headers in the implementations of this client do not get added
- * in blocking version, whereas in NB version defaultHeaders get added.
- * the difference is in convertToBasicHeaders vs basicHeaders
- */
- val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(headers)
- return when (HttpMethod.resolve(methodType)) {
- HttpMethod.DELETE -> delete(path, convertedHeaders, String::class.java)
- HttpMethod.GET -> get(path, convertedHeaders, String::class.java)
- HttpMethod.POST -> post(path, request, convertedHeaders, String::class.java)
- HttpMethod.PUT -> put(path, request, convertedHeaders, String::class.java)
- HttpMethod.PATCH -> patch(path, request, convertedHeaders, String::class.java)
- else -> throw BluePrintProcessorException(
- "Unsupported methodType($methodType) attempted on path($path)"
- )
- }
- }
-
- // TODO: convert to multi-map
- fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
- return headers.map { BasicHeader(it.key, it.value) }.toTypedArray()
- }
+ ): WebClientResponse<String>
- fun <T> delete(path: String, headers: Array<BasicHeader>, responseType: Class<T>): WebClientResponse<T> {
- val httpDelete = HttpDelete(host(path))
- RestLoggerService.httpInvoking(headers)
- httpDelete.setHeaders(headers)
- return performCallAndExtractTypedWebClientResponse(httpDelete, responseType)
- }
-
- fun <T> get(path: String, headers: Array<BasicHeader>, responseType: Class<T>): WebClientResponse<T> {
- val httpGet = HttpGet(host(path))
- RestLoggerService.httpInvoking(headers)
- httpGet.setHeaders(headers)
- return performCallAndExtractTypedWebClientResponse(httpGet, responseType)
- }
-
- fun <T> post(path: String, request: Any, headers: Array<BasicHeader>, responseType: Class<T>): WebClientResponse<T> {
- val httpPost = HttpPost(host(path))
- val entity = StringEntity(strRequest(request))
- httpPost.entity = entity
- RestLoggerService.httpInvoking(headers)
- httpPost.setHeaders(headers)
- return performCallAndExtractTypedWebClientResponse(httpPost, responseType)
- }
-
- fun <T> put(path: String, request: Any, headers: Array<BasicHeader>, responseType: Class<T>): WebClientResponse<T> {
- val httpPut = HttpPut(host(path))
- val entity = StringEntity(strRequest(request))
- httpPut.entity = entity
- RestLoggerService.httpInvoking(headers)
- httpPut.setHeaders(headers)
- return performCallAndExtractTypedWebClientResponse(httpPut, responseType)
- }
-
- fun <T> patch(path: String, request: Any, headers: Array<BasicHeader>, responseType: Class<T>): WebClientResponse<T> {
- val httpPatch = HttpPatch(host(path))
- val entity = StringEntity(strRequest(request))
- httpPatch.entity = entity
- RestLoggerService.httpInvoking(headers)
- httpPatch.setHeaders(headers)
- return performCallAndExtractTypedWebClientResponse(httpPatch, responseType)
- }
-
- /**
- * Perform the HTTP call and return HTTP status code and body.
- * @param httpUriRequest {@link HttpUriRequest} object
- * @return {@link WebClientResponse} object
- * http client may throw IOException and ClientProtocolException on error
- */
-
- @Throws(IOException::class, ClientProtocolException::class)
- private fun <T> performCallAndExtractTypedWebClientResponse(
- httpUriRequest: HttpUriRequest,
- responseType: Class<T>
- ):
- WebClientResponse<T> {
- val httpResponse = httpClient().execute(httpUriRequest)
- val statusCode = httpResponse.statusLine.statusCode
- httpResponse.entity.content.use {
- val body = getResponse(it, responseType)
- return WebClientResponse(statusCode, body)
- }
- }
-
- suspend fun getNB(path: String): WebClientResponse<String> {
- return getNB(path, null, String::class.java)
- }
-
- suspend fun getNB(path: String, additionalHeaders: Array<BasicHeader>?): WebClientResponse<String> {
- return getNB(path, additionalHeaders, String::class.java)
- }
-
- suspend fun <T> getNB(path: String, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>):
- WebClientResponse<T> = withContext(Dispatchers.IO) {
- get(path, additionalHeaders!!, responseType)
- }
-
- suspend fun postNB(path: String, request: Any): WebClientResponse<String> {
- return postNB(path, request, null, String::class.java)
- }
-
- suspend fun postNB(path: String, request: Any, additionalHeaders: Array<BasicHeader>?): WebClientResponse<String> {
- return postNB(path, request, additionalHeaders, String::class.java)
- }
-
- suspend fun <T> postNB(
- path: String,
- request: Any,
- additionalHeaders: Array<BasicHeader>?,
- responseType: Class<T>
- ): WebClientResponse<T> = withContext(Dispatchers.IO) {
- post(path, request, additionalHeaders!!, responseType)
- }
-
- suspend fun putNB(path: String, request: Any): WebClientResponse<String> {
- return putNB(path, request, null, String::class.java)
- }
-
- suspend fun putNB(
+ fun exchangeResource(
+ methodType: String,
path: String,
- request: Any,
- additionalHeaders: Array<BasicHeader>?
- ): WebClientResponse<String> {
- return putNB(path, request, additionalHeaders, String::class.java)
- }
+ request: String
+ ): WebClientResponse<String>
- suspend fun <T> putNB(
- path: String,
- request: Any,
- additionalHeaders: Array<BasicHeader>?,
- responseType: Class<T>
- ): WebClientResponse<T> = withContext(Dispatchers.IO) {
- put(path, request, additionalHeaders!!, responseType)
- }
-
- suspend fun <T> deleteNB(path: String): WebClientResponse<String> {
- return deleteNB(path, null, String::class.java)
- }
-
- suspend fun <T> deleteNB(path: String, additionalHeaders: Array<BasicHeader>?):
- WebClientResponse<String> {
- return deleteNB(path, additionalHeaders, String::class.java)
- }
-
- suspend fun <T> deleteNB(path: String, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>):
- WebClientResponse<T> = withContext(Dispatchers.IO) {
- delete(path, additionalHeaders!!, responseType)
- }
-
- suspend fun <T> patchNB(path: String, request: Any, additionalHeaders: Array<BasicHeader>?, responseType: Class<T>):
- WebClientResponse<T> = withContext(Dispatchers.IO) {
- patch(path, request, additionalHeaders!!, responseType)
- }
-
- suspend fun exchangeNB(methodType: String, path: String, request: Any): WebClientResponse<String> {
- return exchangeNB(
- methodType, path, request, hashMapOf(),
- String::class.java
- )
- }
+ suspend fun exchangeNB(methodType: String, path: String, request: Any): WebClientResponse<String>
suspend fun exchangeNB(methodType: String, path: String, request: Any, additionalHeaders: Map<String, String>?):
- WebClientResponse<String> {
- return exchangeNB(methodType, path, request, additionalHeaders, String::class.java)
- }
+ WebClientResponse<String>
suspend fun <T> exchangeNB(
methodType: String,
@@ -259,75 +53,25 @@ interface BlueprintWebClientService {
request: Any,
additionalHeaders: Map<String, String>?,
responseType: Class<T>
- ): WebClientResponse<T> {
+ ): WebClientResponse<T>
- // TODO: possible inconsistency
- // NOTE: this basic headers function is different from non-blocking
- val convertedHeaders: Array<BasicHeader> = basicHeaders(additionalHeaders!!)
- return when (HttpMethod.resolve(methodType)) {
- HttpMethod.GET -> getNB(path, convertedHeaders, responseType)
- HttpMethod.POST -> postNB(path, request, convertedHeaders, responseType)
- HttpMethod.DELETE -> deleteNB(path, convertedHeaders, responseType)
- HttpMethod.PUT -> putNB(path, request, convertedHeaders, responseType)
- HttpMethod.PATCH -> patchNB(path, request, convertedHeaders, responseType)
- else -> throw BluePrintProcessorException("Unsupported methodType($methodType)")
- }
- }
-
- private fun strRequest(request: Any): String {
- return when (request) {
- is String -> request.toString()
- is JsonNode -> request.toString()
- else -> JacksonUtils.getJson(request)
- }
- }
-
- private fun <T> getResponse(it: InputStream, responseType: Class<T>): T {
- return if (responseType == String::class.java) {
- IOUtils.toString(it, Charset.defaultCharset()) as T
- } else {
- JacksonUtils.readValue(it, responseType)!!
- }
- }
-
- private fun basicHeaders(headers: Map<String, String>?):
- Array<BasicHeader> {
- val basicHeaders = mutableListOf<BasicHeader>()
- defaultHeaders().forEach { (name, value) ->
- basicHeaders.add(BasicHeader(name, value))
- }
- headers?.forEach { name, value ->
- basicHeaders.add(BasicHeader(name, value))
+ /** High performance non blocking Retry function, If execution block [block] throws BluePrintRetryException
+ * exception then this will perform wait and retrigger accoring to times [times] with delay [delay]
+ */
+ suspend fun <T> retry(
+ times: Int = 1,
+ initialDelay: Long = 0,
+ delay: Long = 1000,
+ block: suspend (Int) -> T
+ ): T {
+ val exceptionBlock = { e: Exception ->
+ if (e !is BluePrintRetryException) {
+ throw e
}
- return basicHeaders.toTypedArray()
}
-
- // Non Blocking Rest Implementation
- suspend fun httpClientNB(): CloseableHttpClient {
- return HttpClients.custom()
- .addInterceptorFirst(WebClientUtils.logRequest())
- .addInterceptorLast(WebClientUtils.logResponse())
- .build()
+ return BluePrintIOUtils.retry(times, initialDelay, delay, block, exceptionBlock)
}
// TODO maybe there could be cases where we care about return headers?
data class WebClientResponse<T>(val status: Int, val body: T)
-
- fun verifyAdditionalHeaders(restClientProperties: RestClientProperties): Map<String, String> {
- val customHeaders: MutableMap<String, String> = mutableMapOf()
- // Extract additionalHeaders from the requestProperties and
- // throw an error if HttpHeaders.AUTHORIZATION key (headers are case-insensitive)
- restClientProperties.additionalHeaders?.let {
- if (it.keys.map { k -> k.toLowerCase().trim() }.contains(HttpHeaders.AUTHORIZATION.toLowerCase())) {
- val errMsg = "Error in definition of endpoint ${restClientProperties.url}." +
- " User-supplied \"additionalHeaders\" cannot contain AUTHORIZATION header with" +
- " auth-type \"${RestLibConstants.TYPE_BASIC_AUTH}\""
- WebClientUtils.log.error(errMsg)
- throw BluePrintProcessorException(errMsg)
- } else {
- customHeaders.putAll(it)
- }
- }
- return customHeaders
- }
}
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt
index a8d79b6fa..602609b6a 100644
--- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/SSLRestClientService.kt
@@ -24,6 +24,7 @@ import org.apache.http.impl.client.HttpClients
import org.apache.http.message.BasicHeader
import org.apache.http.ssl.SSLContextBuilder
import org.onap.ccsdk.cds.blueprintsprocessor.rest.BasicAuthRestClientProperties
+import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties
import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLBasicAuthRestClientProperties
import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLRestClientProperties
import org.onap.ccsdk.cds.blueprintsprocessor.rest.SSLTokenAuthRestClientProperties
@@ -35,8 +36,8 @@ import java.io.FileInputStream
import java.security.KeyStore
import java.security.cert.X509Certificate
-class SSLRestClientService(private val restClientProperties: SSLRestClientProperties) :
- BlueprintWebClientService {
+open class SSLRestClientService(private val restClientProperties: SSLRestClientProperties) :
+ BaseBlueprintWebClientService<SSLRestClientProperties>() {
var auth: BlueprintWebClientService? = null
@@ -44,7 +45,11 @@ class SSLRestClientService(private val restClientProperties: SSLRestClientProper
auth = getAuthService()
}
- private fun getAuthService(): BlueprintWebClientService? {
+ override fun getRestClientProperties(): SSLRestClientProperties {
+ return restClientProperties
+ }
+
+ private fun getAuthService(): BaseBlueprintWebClientService<RestClientProperties>? {
// type,url and additional headers don't get carried over to TokenAuthRestClientProperties from SSLTokenAuthRestClientProperties
// set them in auth obj to be consistent. TODO: refactor
return when (restClientProperties) {
@@ -81,10 +86,6 @@ class SSLRestClientService(private val restClientProperties: SSLRestClientProper
)
}
- override fun host(uri: String): String {
- return restClientProperties.url + uri
- }
-
override fun httpClient(): CloseableHttpClient {
val keystoreInstance = restClientProperties.keyStoreInstance
@@ -117,14 +118,10 @@ class SSLRestClientService(private val restClientProperties: SSLRestClientProper
return HttpClients.custom()
.addInterceptorFirst(WebClientUtils.logRequest())
.addInterceptorLast(WebClientUtils.logResponse())
+ .setDefaultRequestConfig(getRequestConfig())
.setSSLSocketFactory(csf).build()
}
- // Non Blocking Rest Implementation
- override suspend fun httpClientNB(): CloseableHttpClient {
- return httpClient()
- }
-
override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
val mergedDefaultAndSuppliedHeaders = defaultHeaders().plus(headers)
// During the initialization, getAuthService() sets the auth variable.
diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt
index 600eedf15..34e4a9e20 100644
--- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt
+++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt
@@ -21,11 +21,15 @@ import org.onap.ccsdk.cds.blueprintsprocessor.rest.TokenAuthRestClientProperties
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
-class TokenAuthRestClientService(
+open class TokenAuthRestClientService(
private val restClientProperties:
TokenAuthRestClientProperties
) :
- BlueprintWebClientService {
+ BaseBlueprintWebClientService<TokenAuthRestClientProperties>() {
+
+ override fun getRestClientProperties(): TokenAuthRestClientProperties {
+ return restClientProperties
+ }
override fun defaultHeaders(): Map<String, String> {
return mapOf(
@@ -45,8 +49,4 @@ class TokenAuthRestClientService(
}
return super.convertToBasicHeaders(customHeaders)
}
-
- override fun host(uri: String): String {
- return restClientProperties.url + uri
- }
}