Refactor rest clients and support timeouts
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / commons / rest-lib / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / rest / service / BlueprintWebClientService.kt
index 94a5753..ed52e62 100644 (file)
@@ -1,5 +1,8 @@
 /*
  * 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.
 
 package org.onap.ccsdk.cds.blueprintsprocessor.rest.service
 
-import org.apache.commons.io.IOUtils
-import org.apache.http.client.methods.*
-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.utils.WebClientUtils
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
-import org.springframework.http.HttpMethod
-import java.nio.charset.Charset
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintRetryException
+import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintIOUtils
 
 interface BlueprintWebClientService {
-
     fun defaultHeaders(): Map<String, String>
+    fun convertToBasicHeaders(
+        mergedDefaultAndSuppliedHeaders: Map<String, String>
+    ): Array<BasicHeader>
 
-    fun host(uri: String): String
+    fun exchangeResource(
+        methodType: String,
+        path: String,
+        request: String,
+        headers: Map<String, String>
+    ): WebClientResponse<String>
 
-    fun httpClient(): CloseableHttpClient {
-        return HttpClients.custom()
-            .addInterceptorFirst(WebClientUtils.logRequest())
-            .addInterceptorLast(WebClientUtils.logResponse())
-            .build()
-    }
+    fun exchangeResource(
+        methodType: String,
+        path: String,
+        request: String
+    ): WebClientResponse<String>
 
-    fun exchangeResource(methodType: String, path: String, request: String): String {
-        return this.exchangeResource(methodType, path, request, defaultHeaders())
-    }
+    suspend fun exchangeNB(methodType: String, path: String, request: Any): WebClientResponse<String>
 
-    fun exchangeResource(methodType: String, path: String, request: String, headers: Map<String, String>): String {
-        val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(headers)
-        return when (HttpMethod.resolve(methodType)) {
-            HttpMethod.DELETE -> delete(path, convertedHeaders)
-            HttpMethod.GET -> get(path, convertedHeaders)
-            HttpMethod.POST -> post(path, request, convertedHeaders)
-            HttpMethod.PUT -> put(path, request, convertedHeaders)
-            HttpMethod.PATCH -> patch(path, request, convertedHeaders)
-            else -> throw BluePrintProcessorException("Unsupported methodType($methodType)")
-        }
-    }
+    suspend fun exchangeNB(methodType: String, path: String, request: Any, additionalHeaders: Map<String, String>?):
+        WebClientResponse<String>
 
-    fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
-        return headers.map{ BasicHeader(it.key, it.value)}.toTypedArray()
-    }
-
-    fun delete(path: String, headers: Array<BasicHeader>): String {
-        val httpDelete = HttpDelete(host(path))
-        httpDelete.setHeaders(headers)
-        httpClient().execute(httpDelete).entity.content.use {
-            return IOUtils.toString(it, Charset.defaultCharset())
-        }
-    }
+    suspend fun <T> exchangeNB(
+        methodType: String,
+        path: String,
+        request: Any,
+        additionalHeaders: Map<String, String>?,
+        responseType: Class<T>
+    ): WebClientResponse<T>
 
-    fun get(path: String, headers: Array<BasicHeader>): String {
-        val httpGet = HttpGet(host(path))
-        httpGet.setHeaders(headers)
-        httpClient().execute(httpGet).entity.content.use {
-            return IOUtils.toString(it, Charset.defaultCharset())
+    /** 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 post(path: String, request: String, headers: Array<BasicHeader>): String {
-        val httpPost = HttpPost(host(path))
-        val entity = StringEntity(request)
-        httpPost.entity = entity
-        httpPost.setHeaders(headers)
-        httpClient().execute(httpPost).entity.content.use {
-            return IOUtils.toString(it, Charset.defaultCharset())
-        }
-    }
-
-    fun put(path: String, request: String, headers: Array<BasicHeader>): String {
-        val httpPut = HttpPut(host(path))
-        val entity = StringEntity(request)
-        httpPut.entity = entity
-        httpPut.setHeaders(headers)
-        httpClient().execute(httpPut).entity.content.use {
-            return IOUtils.toString(it, Charset.defaultCharset())
-        }
-    }
-
-    fun patch(path: String, request: String, headers: Array<BasicHeader>): String {
-        val httpPatch = HttpPatch(host(path))
-        val entity = StringEntity(request)
-        httpPatch.entity = entity
-        httpPatch.setHeaders(headers)
-        httpClient().execute(httpPatch).entity.content.use {
-            return IOUtils.toString(it, Charset.defaultCharset())
-        }
-    }
-}
\ No newline at end of file
+    // TODO maybe there could be cases where we care about return headers?
+    data class WebClientResponse<T>(val status: Int, val body: T)
+}