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