Merge "use config value instead hard code of url"
[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 javax.ws.rs.core.Response
25 import java.net.URLEncoder
26
27 import org.apache.commons.codec.binary.Base64
28 import org.apache.commons.lang3.*
29 import org.camunda.bpm.engine.delegate.BpmnError
30 import org.camunda.bpm.engine.delegate.DelegateExecution
31
32 import groovy.json.*
33
34 import org.json.JSONObject
35
36 import org.onap.so.bpmn.core.UrnPropertiesReader
37 import org.onap.so.bpmn.core.WorkflowException
38 import org.onap.so.bpmn.core.domain.RollbackData
39 import org.onap.so.bpmn.core.json.JsonUtils
40 import org.onap.so.client.HttpClient
41 import org.onap.so.logger.MessageEnum
42 import org.onap.so.logger.MsoLogger
43 import org.onap.so.utils.TargetEntity
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                         URL url = new URL(sdncAdapterUrl);
209
210                         HttpClient httpClient = new HttpClient(url, "application/json", TargetEntity.SDNC_ADAPTER)                      
211                         httpClient.addAdditionalHeader("X-ONAP-RequestID", execution.getVariable("mso-request-id"))
212                         httpClient.addAdditionalHeader("X-ONAP-InvocationID", UUID.randomUUID().toString())
213                         httpClient.addAdditionalHeader("X-ONAP-PartnerName", "SO-SDNCAdapter")
214                         httpClient.addAdditionalHeader("mso-request-id", execution.getVariable("mso-request-id"))
215                         httpClient.addAdditionalHeader("mso-service-instance-id", execution.getVariable("mso-service-instance-id"))
216                         httpClient.addAdditionalHeader("Authorization", execution.getVariable(prefix + "basicAuthHeaderValue"))
217
218                         Response response
219
220                         if ("GET".equals(sdncAdapterMethod)) {
221                                 response = httpClient.get()
222                         } else if ("PUT".equals(sdncAdapterMethod)) {
223                                 response = httpClient.put(sdncAdapterRequest)
224                         } else if ("POST".equals(sdncAdapterMethod)) {
225                                 response = httpClient.post(sdncAdapterRequest)
226                         } else if ("DELETE".equals(sdncAdapterMethod)) {
227                                 response = httpClient.delete(sdncAdapterRequest)
228                         } else {
229                                 String msg = 'Unsupported HTTP method "' + sdncAdapterMethod + '" in ' + method + ": " + e
230                                 msoLogger.debug(msg)
231                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
232                                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
233                         }
234
235                         execution.setVariable(prefix + "sdncAdapterStatusCode", response.getStatus())
236                         if(response.hasEntity()){
237                                 execution.setVariable(prefix + "sdncAdapterResponse", response.readEntity(String.class))
238                         }
239                 } catch (BpmnError e) {
240                         throw e
241                 } catch (Exception e) {
242                         String msg = 'Caught exception in ' + method + ": " + e
243                         msoLogger.debug(msg, e)
244                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
245                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
246                 }
247         }
248
249         /**
250          * Processes a callback.
251          */
252         public void processCallback(DelegateExecution execution){
253                 def method = getClass().getSimpleName() + '.processCallback(' +
254                         'execution=' + execution.getId() +
255                         ')'
256                 msoLogger.trace('Entered ' + method)
257
258                 String prefix = execution.getVariable('prefix')
259                 String callback = execution.getVariable('SDNCAResponse_MESSAGE')
260                 String requestId = execution.getVariable("mso-request-id");
261                 String serviceInstanceId = execution.getVariable("mso-service-instance-id")
262                 utils.logContext(requestId, serviceInstanceId)
263                 msoLogger.debug("Incoming SDNC Rest Callback is: " + callback)
264
265                 try {
266                         int callbackNumber = 1
267                         while (execution.getVariable(prefix + 'callback' + callbackNumber) != null) {
268                                 ++callbackNumber
269                         }
270
271                         execution.setVariable(prefix + 'callback' + callbackNumber, callback)
272                         execution.removeVariable('SDNCAResponse_MESSAGE')
273
274                         String responseType = jsonUtil.getJsonRootProperty(callback)
275
276                         // Get the ackFinalIndicator and make sure it's either Y or N.  Default to Y.
277                         String ackFinalIndicator = jsonUtil.getJsonValue(callback, responseType + ".ackFinalIndicator")
278
279                         if (!'N'.equals(ackFinalIndicator)) {
280                                 ackFinalIndicator = 'Y'
281                         }
282
283                         execution.setVariable(prefix + "ackFinalIndicator", ackFinalIndicator)
284
285                         if (responseType.endsWith('Error')) {
286                                 sdncAdapterBuildWorkflowException(execution, callback)
287                         }
288                 } catch (Exception e) {
289                         callback = callback == null || String.valueOf(callback).isEmpty() ? "NONE" : callback
290                         String msg = "Received error from SDNCAdapter: " + callback
291                         msoLogger.debug(getProcessKey(execution) + ': ' + msg)
292                         exceptionUtil.buildWorkflowException(execution, 5300, msg)
293                 }
294         }
295
296         /**
297          * Tries to parse the response as XML to extract the information to create
298          * a WorkflowException.  If the response cannot be parsed, a more generic
299          * WorkflowException is created.
300          */
301         public void sdncAdapterBuildWorkflowException(DelegateExecution execution, String response) {
302                 try {
303                         String responseType = jsonUtil.getJsonRootProperty(response)
304                         String responseCode = jsonUtil.getJsonValue(response, responseType + ".responseCode")
305                         String responseMessage = jsonUtil.getJsonValue(response, responseType + ".responseMessage")
306
307                         String info = ""
308
309                         if (responseCode != null && !responseCode.isEmpty()) {
310                                  info += " responseCode='" + responseCode + "'"
311                         }
312
313                         if (responseMessage != null && !responseMessage.isEmpty()) {
314                                  info += " responseMessage='" + responseMessage + "'"
315                         }
316
317                         // Note: the mapping function handles a null or empty responseCode
318                         int mappedResponseCode = Integer.parseInt(exceptionUtil.MapSDNCResponseCodeToErrorCode(responseCode));
319                         exceptionUtil.buildWorkflowException(execution, mappedResponseCode, "Received " + responseType +
320                                 " from SDNCAdapter:" + info)
321                 } catch (Exception e) {
322                         response = response == null || String.valueOf(response).isEmpty() ? "NONE" : response
323                         exceptionUtil.buildWorkflowException(execution, 5300, "Received error from SDNCAdapter: " + response)
324                 }
325         }
326
327         /**
328          * Gets the last callback request from the execution, or null if there was no callback.
329          */
330         public String getLastCallback(DelegateExecution execution) {
331                 def method = getClass().getSimpleName() + '.getLastCallback(' +
332                         'execution=' + execution.getId() +
333                         ')'
334                 msoLogger.trace('Entered ' + method)
335
336                 String prefix = execution.getVariable('prefix')
337
338                 try {
339                         int callbackNumber = 1
340                         String callback = null
341
342                         while (true) {
343                                 String thisCallback = (String) execution.getVariable(prefix + 'callback' + callbackNumber)
344
345                                 if (thisCallback == null) {
346                                         break
347                                 }
348
349                                 callback = thisCallback
350                                 ++callbackNumber
351                         }
352
353                         return callback
354                 } catch (Exception e) {
355                         String msg = 'Caught exception in ' + method + ": " + e
356                         msoLogger.debug(msg)
357                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
358                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
359                 }
360         }
361
362         /**
363          * Sets the timeout value to wait for the next notification.
364          */
365         public void setTimeoutValue(DelegateExecution execution) {
366                 def method = getClass().getSimpleName() + '.setTimeoutValue(' +
367                         'execution=' + execution.getId() +
368                         ')'
369                 msoLogger.trace('Entered ' + method)
370
371                 String prefix = execution.getVariable('prefix')
372
373                 try {
374                         def timeoutValue = UrnPropertiesReader.getVariable("mso.adapters.sdnc.timeout", execution)
375
376                         if (execution.getVariable(prefix + 'callback1') != null) {
377                                 // Waiting for subsequent notifications
378                         }
379                 } catch (Exception e) {
380                         String msg = 'Caught exception in ' + method + ": " + e
381                         msoLogger.debug(msg)
382                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
383                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
384                 }
385         }
386 }