replace all fixed wiremock ports
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / SDNCAdapterRestV1.groovy
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.so.bpmn.common.scripts
24
25 import org.onap.so.client.HttpClientFactory
26 import org.onap.so.logger.ErrorCode
27
28 import java.text.SimpleDateFormat
29 import javax.ws.rs.core.Response
30 import java.net.URLEncoder
31
32 import org.apache.commons.codec.binary.Base64
33 import org.apache.commons.lang3.*
34 import org.camunda.bpm.engine.delegate.BpmnError
35 import org.camunda.bpm.engine.delegate.DelegateExecution
36
37 import groovy.json.*
38
39 import org.json.JSONObject
40
41 import org.onap.so.bpmn.core.UrnPropertiesReader
42 import org.onap.so.bpmn.core.WorkflowException
43 import org.onap.so.bpmn.core.domain.RollbackData
44 import org.onap.so.bpmn.core.json.JsonUtils
45 import org.onap.so.client.HttpClient
46 import org.onap.so.logger.MessageEnum
47 import org.slf4j.Logger
48 import org.slf4j.LoggerFactory
49 import org.onap.so.utils.TargetEntity
50
51
52
53
54 class SDNCAdapterRestV1 extends AbstractServiceTaskProcessor {
55     private static final Logger logger = LoggerFactory.getLogger( SDNCAdapterRestV1.class);
56
57
58         ExceptionUtil exceptionUtil = new ExceptionUtil()
59         JsonUtils jsonUtil = new JsonUtils()
60
61         /**
62          * Processes the incoming request.
63          */
64         public void preProcessRequest (DelegateExecution execution) {
65                 def method = getClass().getSimpleName() + '.preProcessRequest(' +
66                         'execution=' + execution.getId() +
67                         ')'
68                 logger.trace('Entered ' + method)
69
70                 def prefix="SDNCREST_"
71                 execution.setVariable("prefix", prefix)
72                 setSuccessIndicator(execution, false)
73
74                 try {
75                         // Determine the request type and log the request
76
77                         String request = validateRequest(execution, "mso-request-id")
78                         String requestType = jsonUtil.getJsonRootProperty(request)
79                         execution.setVariable(prefix + 'requestType', requestType)
80                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
81
82                         // Determine the SDNCAdapter endpoint
83
84                         String sdncAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.sdnc.rest.endpoint", execution)
85
86                         if (sdncAdapterEndpoint == null || sdncAdapterEndpoint.isEmpty()) {
87                                 String msg = getProcessKey(execution) + ': mso:adapters:sdnc:rest:endpoint URN mapping is not defined'
88                                 logger.debug(msg)
89                                 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
90                                                 ErrorCode.UnknownError.getValue());
91                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
92                         }
93
94                         while (sdncAdapterEndpoint.endsWith('/')) {
95                                 sdncAdapterEndpoint = sdncAdapterEndpoint.substring(0, sdncAdapterEndpoint.length()-1)
96                         }
97
98                         String sdncAdapterMethod = null
99                         String sdncAdapterUrl = null
100                         String sdncAdapterRequest = request
101
102                         if ('SDNCServiceRequest'.equals(requestType)) {
103                                 // Get the sdncRequestId from the request
104
105                                 String sdncRequestId = jsonUtil.getJsonValue(request, requestType + ".sdncRequestId")
106
107                                 if (sdncRequestId == null || sdncRequestId.isEmpty()) {
108                                         String msg = getProcessKey(execution) + ': no sdncRequestId in ' + requestType
109                                         logger.debug(msg)
110                                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
111                                                         ErrorCode.UnknownError.getValue());
112                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
113                                 }
114
115                                 execution.setVariable('SDNCAResponse_CORRELATOR', sdncRequestId)
116                                 logger.debug(getProcessKey(execution) + ': SDNCAResponse_CORRELATOR = ' + sdncRequestId)
117
118                                 // Get the bpNotificationUrl from the request (just to make sure it's there)
119
120                                 String bpNotificationUrl = jsonUtil.getJsonValue(request, requestType + ".bpNotificationUrl")
121
122                                 if (bpNotificationUrl == null || bpNotificationUrl.isEmpty()) {
123                                         String msg = getProcessKey(execution) + ': no bpNotificationUrl in ' + requestType
124                                         logger.debug(msg)
125                                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
126                                                         ErrorCode.UnknownError.getValue());
127                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
128                                 }
129
130                                 sdncAdapterMethod = 'POST'
131                                 sdncAdapterUrl = sdncAdapterEndpoint
132
133                                 RollbackData rollbackData = new RollbackData()
134                                 rollbackData.setRequestId(sdncRequestId)
135                                 rollbackData.getAdditionalData().put("service", jsonUtil.getJsonValue(request, requestType + ".sdncService"))
136                                 rollbackData.getAdditionalData().put("operation", jsonUtil.getJsonValue(request, requestType + ".sdncOperation"))
137                                 execution.setVariable("RollbackData", rollbackData)
138
139                         } else {
140                                 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
141                                 logger.debug(msg)
142                                 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
143                                                 ErrorCode.UnknownError.getValue());
144                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
145                         }
146
147                         execution.setVariable(prefix + 'sdncAdapterMethod', sdncAdapterMethod)
148                         execution.setVariable(prefix + 'sdncAdapterUrl', sdncAdapterUrl)
149                         execution.setVariable(prefix + 'sdncAdapterRequest', sdncAdapterRequest)
150
151                         // Get the Basic Auth credentials for the SDNCAdapter (yes... we ARE using the PO adapters credentials)
152
153                         String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth", execution)
154
155                         if (basicAuthValue == null || basicAuthValue.isEmpty()) {
156                                 logger.debug(getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined")
157                                 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
158                                                 getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN",
159                                                 ErrorCode.UnknownError.getValue());
160                         } else {
161                                 try {
162                                         def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
163                                         execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
164                                 } catch (IOException ex) {
165                                         logger.debug(getProcessKey(execution) + ": Unable to encode BasicAuth credentials for SDNCAdapter")
166                                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
167                                                         getProcessKey(execution) + ": Unable to encode BasicAuth credentials for SDNCAdapter",
168                                                         "BPMN", ErrorCode.UnknownError.getValue(), ex);
169                                 }
170                         }
171
172                         // Set the timeout value, e.g. PT5M. It may be specified in the request as the
173                         // bpTimeout value.  If it's not in the request, use the URN mapping value.
174
175                         String timeout = jsonUtil.getJsonValue(request, requestType + ".bpTimeout")
176
177                         // in addition to null/empty, also need to verify that the timer value is a valid duration "P[n]T[n]H|M|S"
178                         String timerRegex = "PT[0-9]+[HMS]";
179                         if (timeout == null || timeout.isEmpty() || !timeout.matches(timerRegex)) {
180                                 logger.debug(getProcessKey(execution) + ': preProcessRequest(): null/empty/invalid bpTimeout value. Using "mso.adapters.sdnc.timeout"')
181                                 timeout = UrnPropertiesReader.getVariable("mso.adapters.sdnc.timeout", execution)
182                         }
183
184                         // the timeout could still be null at this point if the config parm is missing/undefined
185                         // forced to log (so OPs can fix the config) and temporarily use a hard coded value of 10 seconds
186                         if (timeout == null) {
187                                 msoLogger.warnSimple('preProcessRequest()', 'property "mso.adapters.sdnc.timeout" is missing/undefined. Using "PT10S"')
188                                 timeout = "PT10S"
189                         }
190
191                         execution.setVariable(prefix + 'timeout', timeout)
192                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'timeout = ' + timeout)
193                 } catch (BpmnError e) {
194                         throw e
195                 } catch (Exception e) {
196                         String msg = 'Caught exception in ' + method + ": " + e
197                         logger.debug(msg)
198                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
199                                         ErrorCode.UnknownError.getValue());
200                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
201                 }
202         }
203
204         /**
205          * Sends the request to the SDNC adapter.
206          */
207         public void sendRequestToSDNCAdapter(DelegateExecution execution) {
208                 def method = getClass().getSimpleName() + '.sendRequestToSDNCAdapter(' +
209                         'execution=' + execution.getId() +
210                         ')'
211                 logger.trace('Entered ' + method)
212
213                 String prefix = execution.getVariable('prefix')
214
215                 try {
216                         String sdncAdapterMethod = execution.getVariable(prefix + 'sdncAdapterMethod')
217                         logger.debug("SDNC Method is: " + sdncAdapterMethod)
218                         String sdncAdapterUrl = execution.getVariable(prefix + 'sdncAdapterUrl')
219                         logger.debug("SDNC Url is: " + sdncAdapterUrl)
220                         String sdncAdapterRequest = execution.getVariable(prefix + 'sdncAdapterRequest')
221                         logger.debug("SDNC Rest Request is: " + sdncAdapterRequest)
222
223                         URL url = new URL(sdncAdapterUrl);
224
225                         HttpClient httpClient = new HttpClientFactory().newJsonClient(url, TargetEntity.SDNC_ADAPTER)
226                         httpClient.addAdditionalHeader("X-ONAP-RequestID", execution.getVariable("mso-request-id"))
227                         httpClient.addAdditionalHeader("X-ONAP-InvocationID", UUID.randomUUID().toString())
228                         httpClient.addAdditionalHeader("X-ONAP-PartnerName", "SO-SDNCAdapter")
229                         httpClient.addAdditionalHeader("mso-request-id", execution.getVariable("mso-request-id"))
230                         httpClient.addAdditionalHeader("mso-service-instance-id", execution.getVariable("mso-service-instance-id"))
231                         httpClient.addAdditionalHeader("Authorization", execution.getVariable(prefix + "basicAuthHeaderValue"))
232
233                         Response response
234
235                         if ("GET".equals(sdncAdapterMethod)) {
236                                 response = httpClient.get()
237                         } else if ("PUT".equals(sdncAdapterMethod)) {
238                                 response = httpClient.put(sdncAdapterRequest)
239                         } else if ("POST".equals(sdncAdapterMethod)) {
240                                 response = httpClient.post(sdncAdapterRequest)
241                         } else if ("DELETE".equals(sdncAdapterMethod)) {
242                                 response = httpClient.delete(sdncAdapterRequest)
243                         } else {
244                                 String msg = 'Unsupported HTTP method "' + sdncAdapterMethod + '" in ' + method + ": " + e
245                                 logger.debug(msg)
246                                 logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
247                                                 ErrorCode.UnknownError.getValue());
248                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
249                         }
250
251                         execution.setVariable(prefix + "sdncAdapterStatusCode", response.getStatus())
252                         if(response.hasEntity()){
253                                 execution.setVariable(prefix + "sdncAdapterResponse", response.readEntity(String.class))
254                         }
255                 } catch (BpmnError e) {
256                         throw e
257                 } catch (Exception e) {
258                         String msg = 'Caught exception in ' + method + ": " + e
259                         logger.debug(msg, e)
260                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
261                                         ErrorCode.UnknownError.getValue());
262                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
263                 }
264         }
265
266         /**
267          * Processes a callback.
268          */
269         public void processCallback(DelegateExecution execution){
270                 def method = getClass().getSimpleName() + '.processCallback(' +
271                         'execution=' + execution.getId() +
272                         ')'
273                 logger.trace('Entered ' + method)
274
275                 String prefix = execution.getVariable('prefix')
276                 String callback = execution.getVariable('SDNCAResponse_MESSAGE')
277                 logger.debug("Incoming SDNC Rest Callback is: " + callback)
278
279                 try {
280                         int callbackNumber = 1
281                         while (execution.getVariable(prefix + 'callback' + callbackNumber) != null) {
282                                 ++callbackNumber
283                         }
284
285                         execution.setVariable(prefix + 'callback' + callbackNumber, callback)
286                         execution.removeVariable('SDNCAResponse_MESSAGE')
287
288                         String responseType = jsonUtil.getJsonRootProperty(callback)
289
290                         // Get the ackFinalIndicator and make sure it's either Y or N.  Default to Y.
291                         String ackFinalIndicator = jsonUtil.getJsonValue(callback, responseType + ".ackFinalIndicator")
292
293                         if (!'N'.equals(ackFinalIndicator)) {
294                                 ackFinalIndicator = 'Y'
295                         }
296
297                         execution.setVariable(prefix + "ackFinalIndicator", ackFinalIndicator)
298
299                         if (responseType.endsWith('Error')) {
300                                 sdncAdapterBuildWorkflowException(execution, callback)
301                         }
302                 } catch (Exception e) {
303                         callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
304                         String msg = "Received error from SDNCAdapter: " + callback
305                         logger.debug(getProcessKey(execution) + ': ' + msg)
306                         exceptionUtil.buildWorkflowException(execution, 5300, msg)
307                 }
308         }
309
310         /**
311          * Tries to parse the response as XML to extract the information to create
312          * a WorkflowException.  If the response cannot be parsed, a more generic
313          * WorkflowException is created.
314          */
315         public void sdncAdapterBuildWorkflowException(DelegateExecution execution, String response) {
316                 try {
317                         String responseType = jsonUtil.getJsonRootProperty(response)
318                         String responseCode = jsonUtil.getJsonValue(response, responseType + ".responseCode")
319                         String responseMessage = jsonUtil.getJsonValue(response, responseType + ".responseMessage")
320
321                         String info = ""
322
323                         if (responseCode != null && !responseCode.isEmpty()) {
324                                  info += " responseCode='" + responseCode + "'"
325                         }
326
327                         if (responseMessage != null && !responseMessage.isEmpty()) {
328                                  info += " responseMessage='" + responseMessage + "'"
329                         }
330
331                         // Note: the mapping function handles a null or empty responseCode
332                         int mappedResponseCode = Integer.parseInt(exceptionUtil.MapSDNCResponseCodeToErrorCode(responseCode));
333                         exceptionUtil.buildWorkflowException(execution, mappedResponseCode, "Received " + responseType +
334                                 " from SDNCAdapter:" + info)
335                 } catch (Exception e) {
336                         response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
337                         exceptionUtil.buildWorkflowException(execution, 5300, "Received error from SDNCAdapter: " + response)
338                 }
339         }
340
341         /**
342          * Gets the last callback request from the execution, or null if there was no callback.
343          */
344         public String getLastCallback(DelegateExecution execution) {
345                 def method = getClass().getSimpleName() + '.getLastCallback(' +
346                         'execution=' + execution.getId() +
347                         ')'
348                 logger.trace('Entered ' + method)
349
350                 String prefix = execution.getVariable('prefix')
351
352                 try {
353                         int callbackNumber = 1
354                         String callback = null
355
356                         while (true) {
357                                 String thisCallback = (String) execution.getVariable(prefix + 'callback' + callbackNumber)
358
359                                 if (thisCallback == null) {
360                                         break
361                                 }
362
363                                 callback = thisCallback
364                                 ++callbackNumber
365                         }
366
367                         return callback
368                 } catch (Exception e) {
369                         String msg = 'Caught exception in ' + method + ": " + e
370                         logger.debug(msg)
371                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
372                                         ErrorCode.UnknownError.getValue());
373                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
374                 }
375         }
376
377         /**
378          * Sets the timeout value to wait for the next notification.
379          */
380         public void setTimeoutValue(DelegateExecution execution) {
381                 def method = getClass().getSimpleName() + '.setTimeoutValue(' +
382                         'execution=' + execution.getId() +
383                         ')'
384                 logger.trace('Entered ' + method)
385
386                 String prefix = execution.getVariable('prefix')
387
388                 try {
389                         def timeoutValue = UrnPropertiesReader.getVariable("mso.adapters.sdnc.timeout", execution)
390
391                         if (execution.getVariable(prefix + 'callback1') != null) {
392                                 // Waiting for subsequent notifications
393                         }
394                 } catch (Exception e) {
395                         String msg = 'Caught exception in ' + method + ": " + e
396                         logger.debug(msg)
397                         logger.error("{} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
398                                         ErrorCode.UnknownError.getValue());
399                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
400                 }
401         }
402         
403         public Logger getLogger() {
404                 return logger;
405         }
406 }