Merge "Update vFW CBA for Dublin"
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / commons / rest-lib / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / rest / service / BlueprintWebClientService.kt
1 /*
2  * Copyright © 2017-2019 AT&T, Bell Canada, Nordix Foundation
3  * Modifications Copyright © 2018-2019 IBM.
4  * Modifications Copyright © 2019 Huawei.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package org.onap.ccsdk.cds.blueprintsprocessor.rest.service
20
21 import com.fasterxml.jackson.databind.JsonNode
22 import kotlinx.coroutines.Dispatchers
23 import kotlinx.coroutines.withContext
24 import org.apache.commons.io.IOUtils
25 import org.apache.http.client.methods.HttpDelete
26 import org.apache.http.client.methods.HttpGet
27 import org.apache.http.client.methods.HttpPatch
28 import org.apache.http.client.methods.HttpPost
29 import org.apache.http.client.methods.HttpPut
30 import org.apache.http.entity.StringEntity
31 import org.apache.http.impl.client.CloseableHttpClient
32 import org.apache.http.impl.client.HttpClients
33 import org.apache.http.message.BasicHeader
34 import org.onap.ccsdk.cds.blueprintsprocessor.rest.utils.WebClientUtils
35 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
36 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
37 import org.springframework.http.HttpMethod
38 import java.io.InputStream
39 import java.nio.charset.Charset
40
41 interface BlueprintWebClientService {
42
43     fun defaultHeaders(): Map<String, String>
44
45     fun host(uri: String): String
46
47     fun httpClient(): CloseableHttpClient {
48         return HttpClients.custom()
49                 .addInterceptorFirst(WebClientUtils.logRequest())
50                 .addInterceptorLast(WebClientUtils.logResponse())
51                 .build()
52     }
53
54     fun exchangeResource(methodType: String, path: String, request: String):
55             String {
56         return this.exchangeResource(methodType, path, request,
57                 defaultHeaders())
58     }
59
60     fun exchangeResource(methodType: String, path: String, request: String,
61                          headers: Map<String, String>): String {
62         val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(
63                 headers)
64         return when (HttpMethod.resolve(methodType)) {
65             HttpMethod.DELETE -> delete(path, convertedHeaders)
66             HttpMethod.GET -> get(path, convertedHeaders)
67             HttpMethod.POST -> post(path, request, convertedHeaders)
68             HttpMethod.PUT -> put(path, request, convertedHeaders)
69             HttpMethod.PATCH -> patch(path, request, convertedHeaders)
70             else -> throw BluePrintProcessorException("Unsupported met" +
71                     "hodType($methodType)")
72         }
73     }
74
75     fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
76         return headers.map{ BasicHeader(it.key, it.value)}.toTypedArray()
77     }
78
79     fun delete(path: String, headers: Array<BasicHeader>): String {
80         val httpDelete = HttpDelete(host(path))
81         httpDelete.setHeaders(headers)
82         httpClient().execute(httpDelete).entity.content.use {
83             return IOUtils.toString(it, Charset.defaultCharset())
84         }
85     }
86
87     fun get(path: String, headers: Array<BasicHeader>): String {
88         val httpGet = HttpGet(host(path))
89         httpGet.setHeaders(headers)
90         httpClient().execute(httpGet).entity.content.use {
91             return IOUtils.toString(it, Charset.defaultCharset())
92         }
93     }
94
95     fun post(path: String, request: String, headers: Array<BasicHeader>):
96             String {
97         val httpPost = HttpPost(host(path))
98         val entity = StringEntity(request)
99         httpPost.entity = entity
100         httpPost.setHeaders(headers)
101         httpClient().execute(httpPost).entity.content.use {
102             return IOUtils.toString(it, Charset.defaultCharset())
103         }
104     }
105
106     fun put(path: String, request: String, headers: Array<BasicHeader>):
107             String {
108         val httpPut = HttpPut(host(path))
109         val entity = StringEntity(request)
110         httpPut.entity = entity
111         httpPut.setHeaders(headers)
112         httpClient().execute(httpPut).entity.content.use {
113             return IOUtils.toString(it, Charset.defaultCharset())
114         }
115     }
116
117     fun patch(path: String, request: String, headers: Array<BasicHeader>):
118             String {
119         val httpPatch = HttpPatch(host(path))
120         val entity = StringEntity(request)
121         httpPatch.entity = entity
122         httpPatch.setHeaders(headers)
123         httpClient().execute(httpPatch).entity.content.use {
124             return IOUtils.toString(it, Charset.defaultCharset())
125         }
126     }
127
128
129     suspend fun getNB(path: String): String {
130         return getNB(path, null, String::class.java)
131     }
132
133     suspend fun getNB(path: String, additionalHeaders: Map<String, String>?):
134             String {
135         return getNB(path, additionalHeaders, String::class.java)
136     }
137
138     suspend fun <T> getNB(path: String, additionalHeaders: Map<String, String>?,
139                           responseType: Class<T>): T =
140             withContext(Dispatchers.IO) {
141         val httpGet = HttpGet(host(path))
142         httpGet.setHeaders(basicHeaders(additionalHeaders))
143         httpClientNB().execute(httpGet).entity.content.use {
144             getResponse(it, responseType)
145         }
146     }
147
148     suspend fun postNB(path: String, request: Any): String {
149         return postNB(path, request, null, String::class.java)
150     }
151
152     suspend fun postNB(path: String, request: Any,
153                        additionalHeaders: Map<String, String>?): String {
154         return postNB(path, request, additionalHeaders, String::class.java)
155     }
156
157     suspend fun <T> postNB(path: String, request: Any,
158                            additionalHeaders: Map<String, String>?,
159                            responseType: Class<T>): T =
160             withContext(Dispatchers.IO) {
161                 val httpPost = HttpPost(host(path))
162                 httpPost.entity = StringEntity(strRequest(request))
163                 httpPost.setHeaders(basicHeaders(additionalHeaders))
164                 httpClientNB().execute(httpPost).entity.content.use {
165                     getResponse(it, responseType)
166                 }
167             }
168
169     suspend fun putNB(path: String, request: Any): String {
170         return putNB(path, request, null, String::class.java)
171     }
172
173     suspend fun putNB(path: String, request: Any,
174                       additionalHeaders: Map<String, String>?): String {
175         return putNB(path, request, additionalHeaders, String::class.java)
176     }
177
178     suspend fun <T> putNB(path: String, request: Any,
179                           additionalHeaders: Map<String, String>?,
180                           responseType: Class<T>): T =
181             withContext(Dispatchers.IO) {
182         val httpPut = HttpPut(host(path))
183         httpPut.entity = StringEntity(strRequest(request))
184         httpPut.setHeaders(basicHeaders(additionalHeaders))
185         httpClientNB().execute(httpPut).entity.content.use {
186             getResponse(it, responseType)
187         }
188     }
189
190     suspend fun <T> deleteNB(path: String): String {
191         return deleteNB(path, null, String::class.java)
192     }
193
194     suspend fun <T> deleteNB(path: String,
195                              additionalHeaders: Map<String, String>?): String {
196         return deleteNB(path, additionalHeaders, String::class.java)
197     }
198
199     suspend fun <T> deleteNB(path: String,
200                              additionalHeaders: Map<String, String>?,
201                              responseType: Class<T>): T =
202             withContext(Dispatchers.IO) {
203         val httpDelete = HttpDelete(host(path))
204         httpDelete.setHeaders(basicHeaders(additionalHeaders))
205         httpClient().execute(httpDelete).entity.content.use {
206             getResponse(it, responseType)
207         }
208     }
209
210     suspend fun <T> patchNB(path: String, request: Any,
211                             additionalHeaders: Map<String, String>?,
212                             responseType: Class<T>): T =
213             withContext(Dispatchers.IO) {
214         val httpPatch = HttpPatch(host(path))
215         httpPatch.entity = StringEntity(strRequest(request))
216         httpPatch.setHeaders(basicHeaders(additionalHeaders))
217         httpClient().execute(httpPatch).entity.content.use {
218             getResponse(it, responseType)
219         }
220     }
221
222     suspend fun exchangeNB(methodType: String, path: String, request: Any):
223             String {
224         return exchangeNB(methodType, path, request, hashMapOf(),
225                 String::class.java)
226     }
227
228     suspend fun exchangeNB(methodType: String, path: String, request: Any,
229                            additionalHeaders: Map<String, String>?): String {
230         return exchangeNB(methodType, path, request, additionalHeaders,
231                 String::class.java)
232     }
233
234     suspend fun <T> exchangeNB(methodType: String, path: String, request: Any,
235                                additionalHeaders: Map<String, String>?,
236                                responseType: Class<T>): T {
237
238         return when (HttpMethod.resolve(methodType)) {
239             HttpMethod.GET -> getNB(path, additionalHeaders, responseType)
240             HttpMethod.POST -> postNB(path, request, additionalHeaders,
241                     responseType)
242             HttpMethod.DELETE -> deleteNB(path, additionalHeaders, responseType)
243             HttpMethod.PUT -> putNB(path, request, additionalHeaders,
244                     responseType)
245             HttpMethod.PATCH -> patchNB(path, request, additionalHeaders,
246                     responseType)
247             else -> throw BluePrintProcessorException("Unsupported method" +
248                     "Type($methodType)")
249         }
250     }
251
252     private fun strRequest(request: Any): String {
253         return when (request) {
254             is String -> request.toString()
255             is JsonNode -> request.toString()
256             else -> JacksonUtils.getJson(request)
257         }
258     }
259
260     private fun <T> getResponse(it: InputStream, responseType: Class<T>): T {
261         return if (responseType == String::class.java) {
262             IOUtils.toString(it, Charset.defaultCharset()) as T
263         } else {
264             JacksonUtils.readValue(it, responseType)!!
265         }
266     }
267
268     private fun basicHeaders(headers: Map<String, String>?):
269             Array<BasicHeader> {
270
271         val basicHeaders = mutableListOf<BasicHeader>()
272         defaultHeaders().forEach { name, value ->
273             basicHeaders.add(BasicHeader(name, value))
274         }
275         headers?.forEach { name, value ->
276             basicHeaders.add(BasicHeader(name, value))
277         }
278         return basicHeaders.toTypedArray()
279     }
280
281     // Non Blocking Rest Implementation
282     suspend fun httpClientNB(): CloseableHttpClient {
283         return HttpClients.custom()
284                 .addInterceptorFirst(WebClientUtils.logRequest())
285                 .addInterceptorLast(WebClientUtils.logResponse())
286                 .build()
287     }
288 }