64f54dbd66b62cbaf114d6a9d9696c4e16399f74
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / SDNCAdapterRestV2.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 java.text.SimpleDateFormat
26 import java.net.URLEncoder
27
28 import org.apache.commons.codec.binary.Base64
29 import org.apache.commons.lang3.*
30 import org.camunda.bpm.engine.delegate.BpmnError
31 import org.camunda.bpm.engine.delegate.DelegateExecution
32
33 import groovy.json.*
34
35 import org.json.JSONObject
36
37 import org.onap.so.bpmn.core.WorkflowException
38 import org.onap.so.bpmn.core.json.JsonUtils
39 import org.onap.so.bpmn.core.UrnPropertiesReader
40 import org.onap.so.logger.MessageEnum
41 import org.onap.so.logger.MsoLogger
42 import org.slf4j.Logger
43 import org.slf4j.LoggerFactory
44
45
46
47 /**
48  * This version of SDNCAdapterRest allows for interim notifications to be sent for
49  * any non-final response received from SDNC.
50  */
51 class SDNCAdapterRestV2 extends SDNCAdapterRestV1 {
52     private static final Logger logger = LoggerFactory.getLogger( SDNCAdapterRestV2.class);
53
54
55         ExceptionUtil exceptionUtil = new ExceptionUtil()
56         JsonUtils jsonUtil = new JsonUtils()
57
58         /**
59          * Processes the incoming request.
60          */
61         public void preProcessRequest (DelegateExecution execution) {
62                 def method = getClass().getSimpleName() + '.preProcessRequest(' +
63                         'execution=' + execution.getId() +
64                         ')'
65                 logger.trace('Entered ' + method)
66
67                 def prefix="SDNCREST_"
68                 execution.setVariable("prefix", prefix)
69                 setSuccessIndicator(execution, false)
70
71                 try {
72                         // Determine the request type and log the request
73
74                         String request = validateRequest(execution, "mso-request-id")
75                         String requestType = jsonUtil.getJsonRootProperty(request)
76                         execution.setVariable(prefix + 'requestType', requestType)
77                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'requestType = ' + requestType)
78                         logger.debug('SDNCAdapterRestV2, request: ' + request)
79
80                         // Determine the SDNCAdapter endpoint
81
82                         String sdncAdapterEndpoint = UrnPropertiesReader.getVariable("mso.adapters.sdnc.rest.endpoint",execution)
83
84                         if (sdncAdapterEndpoint == null || sdncAdapterEndpoint.isEmpty()) {
85                                 String msg = getProcessKey(execution) + ': mso:adapters:sdnc:rest:endpoint URN mapping is not defined'
86                                 logger.debug(msg)
87                                 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
88                                                 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
89                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
90                         }
91
92                         while (sdncAdapterEndpoint.endsWith('/')) {
93                                 sdncAdapterEndpoint = sdncAdapterEndpoint.substring(0, sdncAdapterEndpoint.length()-1)
94                         }
95
96                         String sdncAdapterMethod = null
97                         String sdncAdapterUrl = null
98                         String sdncAdapterRequest = request
99
100                         if ('SDNCServiceRequest'.equals(requestType)) {
101                                 // Get the sdncRequestId from the request
102
103                                 String sdncRequestId = jsonUtil.getJsonValue(request, requestType + ".sdncRequestId")
104
105                                 if (sdncRequestId == null || sdncRequestId.isEmpty()) {
106                                         String msg = getProcessKey(execution) + ': no sdncRequestId in ' + requestType
107                                         logger.debug(msg)
108                                         logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
109                                                         MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
110                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
111                                 }
112
113                                 execution.setVariable('SDNCAResponse_CORRELATOR', sdncRequestId)
114                                 logger.debug(getProcessKey(execution) + ': SDNCAResponse_CORRELATOR = ' + sdncRequestId)
115
116                                 // Get the bpNotificationUrl from the request (just to make sure it's there)
117
118                                 String bpNotificationUrl = jsonUtil.getJsonValue(request, requestType + ".bpNotificationUrl")
119
120                                 if (bpNotificationUrl == null || bpNotificationUrl.isEmpty()) {
121                                         String msg = getProcessKey(execution) + ': no bpNotificationUrl in ' + requestType
122                                         logger.debug(msg)
123                                         logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
124                                                         MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
125                                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
126                                 }
127
128                                 sdncAdapterMethod = 'POST'
129                                 sdncAdapterUrl = sdncAdapterEndpoint
130
131                         } else {
132                                 String msg = getProcessKey(execution) + ': Unsupported request type: ' + requestType
133                                 logger.debug(msg)
134                                 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
135                                                 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
136                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
137                         }
138
139                         execution.setVariable(prefix + 'sdncAdapterMethod', sdncAdapterMethod)
140                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'sdncAdapterMethod = ' + sdncAdapterMethod)
141                         execution.setVariable(prefix + 'sdncAdapterUrl', sdncAdapterUrl)
142                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'sdncAdapterUrl = ' + sdncAdapterUrl)
143                         execution.setVariable(prefix + 'sdncAdapterRequest', sdncAdapterRequest)
144                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'sdncAdapterRequest = \n' + sdncAdapterRequest)
145
146                         // Get the Basic Auth credentials for the SDNCAdapter (yes... we ARE using the PO adapters credentials)
147
148                         String basicAuthValue = UrnPropertiesReader.getVariable("mso.adapters.po.auth",execution)
149
150                         if (basicAuthValue == null || basicAuthValue.isEmpty()) {
151                                 logger.debug(getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined")
152                                 logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
153                                                 getProcessKey(execution) + ": mso:adapters:po:auth URN mapping is not defined", "BPMN",
154                                                 MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
155                         } else {
156                                 try {
157                                         def encodedString = utils.getBasicAuth(basicAuthValue, UrnPropertiesReader.getVariable("mso.msoKey", execution))
158                                         execution.setVariable(prefix + 'basicAuthHeaderValue', encodedString)
159                                 } catch (IOException ex) {
160                                         logger.debug(getProcessKey(execution) + ": Unable to encode BasicAuth credentials for SDNCAdapter")
161                                         logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(),
162                                                         getProcessKey(execution) + ": Unable to encode BasicAuth credentials for SDNCAdapter",
163                                                         "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
164                                 }
165                         }
166
167                         // Set the timeout value, e.g. PT5M. It may be specified in the request as the
168                         // bpTimeout value.  If it's not in the request, use the URN mapping value.
169
170                         String timeout = jsonUtil.getJsonValue(request, requestType + ".bpTimeout")
171
172                         // in addition to null/empty, also need to verify that the timer value is a valid duration "P[n]T[n]H|M|S"
173                         String timerRegex = "PT[0-9]+[HMS]";
174                         if (timeout == null || timeout.isEmpty() || !timeout.matches(timerRegex)) {
175                                 logger.debug(getProcessKey(execution) + ': preProcessRequest(): null/empty/invalid bpTimeout value. Using "mso.adapters.sdnc.timeout"')
176                                 timeout = UrnPropertiesReader.getVariable("mso.adapters.sdnc.timeout", execution)
177                         }
178
179                         // the timeout could still be null at this point if the config parm is missing/undefined
180                         // forced to log (so OPs can fix the config) and temporarily use a hard coded value of 10 seconds
181                         if (timeout == null) {
182                                 logger.warn("Service Name: {} Error: {}", 'preProcessRequest()', 'property "mso.adapters.sdnc.timeout" is missing/undefined. Using "PT10S"')
183                                 timeout = "PT10S"
184                         }
185
186                         execution.setVariable(prefix + 'timeout', timeout)
187                         logger.debug(getProcessKey(execution) + ': ' + prefix + 'timeout = ' + timeout)
188                 } catch (BpmnError e) {
189                         throw e
190                 } catch (Exception e) {
191                         String msg = 'Caught exception in ' + method + ": " + e
192                         logger.debug(msg)
193                         logger.error("{} {} {} {} {}", MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), msg, "BPMN",
194                                         MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError.getValue());
195                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
196                 }
197         }
198
199         /**
200          * Processes a callback. Check for possible interim notification.
201          */
202         public void processCallback(DelegateExecution execution){
203                 def method = getClass().getSimpleName() + '.processCallback(' +
204                         'execution=' + execution.getId() +
205                         ')'
206                 logger.trace('Entered ' + method)
207
208                 String prefix = execution.getVariable('prefix')
209                 String callback = execution.getVariable('SDNCAResponse_MESSAGE')
210                 logger.debug("Incoming SDNC Rest Callback is: " + callback)
211
212                 try {
213                         logger.debug(getProcessKey(execution) + ": received callback:\n" + callback)
214
215                         int callbackNumber = 1
216                         while (execution.getVariable(prefix + 'callback' + callbackNumber) != null) {
217                                 ++callbackNumber
218                         }
219
220                         execution.setVariable(prefix + 'callback' + callbackNumber, callback)
221                         execution.removeVariable('SDNCAResponse_MESSAGE')
222
223                         String responseType = jsonUtil.getJsonRootProperty(callback)
224
225                         // Get the ackFinalIndicator and make sure it's either Y or N.  Default to Y.
226                         String ackFinalIndicator = jsonUtil.getJsonValue(callback, responseType + ".ackFinalIndicator")
227
228                         if (!'N'.equals(ackFinalIndicator)) {
229                                 ackFinalIndicator = 'Y'
230                         }
231
232                         execution.setVariable(prefix + "ackFinalIndicator", ackFinalIndicator)
233
234                         if (responseType.endsWith('Error')) {
235                                 sdncAdapterBuildWorkflowException(execution, callback)
236                         }
237
238                         // Check for possible interim notification
239                         execution.setVariable(prefix + "interimNotification", null)
240                         execution.setVariable(prefix + "doInterimNotification", false)
241                         if ('N'.equals(ackFinalIndicator)) {
242                                 def interimNotification = execution.getVariable(prefix + "InterimNotification" + callbackNumber)
243                                 if (interimNotification != null) {
244                                         execution.setVariable(prefix + "interimNotification", interimNotification)
245                                         execution.setVariable(prefix + "doInterimNotification", true)
246                                 }
247                         }
248
249                 } catch (Exception e) {
250                         callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
251                         String msg = "Received error from SDNCAdapter: " + callback
252                         logger.debug(getProcessKey(execution) + ': ' + msg)
253                         exceptionUtil.buildWorkflowException(execution, 5300, msg)
254                 }
255         }
256
257         /**
258          * Prepare to send an interim notification by extracting the variable/value definitions
259          * in the interimNotification JSON object and placing them in the execution.  These
260          * variable/value definitions will be passed to the notification service.
261          */
262         public void prepareInterimNotification(DelegateExecution execution) {
263                 def method = getClass().getSimpleName() + '.prepareInterimNotification(' +
264                         'execution=' + execution.getId() +
265                         ')'
266                 logger.trace('Entered ' + method)
267
268                 String prefix = execution.getVariable('prefix')
269                 logger.debug("Preparing Interim Notification")
270
271                 try {
272                         def interimNotification = execution.getVariable(prefix + "interimNotification")
273                         logger.debug("Preparing Interim Notification:\n" + JsonUtils.prettyJson(interimNotification))
274
275                         for (int i = 0; ; i++) {
276                                 def variable = JsonUtils.getJsonParamValue(interimNotification, 'variableList', 'variable', i)
277
278                                 if (variable == null) {
279                                         break
280                                 }
281
282                                 def String variableName = JsonUtils.getJsonValue(variable, "name")
283                                 if ((variableName != null) && !variableName.isEmpty()) {
284                                         def variableValue = JsonUtils.getJsonValue(variable, "value")
285                                         execution.setVariable(variableName, variableValue)
286                                         logger.debug("Setting "+ variableName + "=" + variableValue)
287                                 }
288                         }
289
290                 } catch (Exception e) {
291                         String msg = "Error preparing interim notification"
292                         logger.debug(getProcessKey(execution) + ': ' + msg)
293                         exceptionUtil.buildWorkflowException(execution, 5300, msg)
294                 }
295         }
296 }