Merge "Fixed sonar issue in QueryGroups.java"
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / ExceptionUtil.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.logger.LoggingAnchor
26 import org.onap.so.logger.ErrorCode
27
28 import static org.apache.commons.lang3.StringUtils.*
29
30 import com.google.common.xml.XmlEscapers
31
32 import org.apache.commons.lang3.*
33 import org.camunda.bpm.engine.delegate.BpmnError
34 import org.camunda.bpm.engine.delegate.DelegateExecution
35 import org.onap.so.bpmn.core.WorkflowException
36 import org.onap.so.logger.MessageEnum
37 import org.onap.so.utils.TargetEntities
38 import org.slf4j.Logger
39 import org.slf4j.LoggerFactory
40
41
42
43 /**
44  * @version 1.0
45  */
46 class ExceptionUtil extends AbstractServiceTaskProcessor {
47     private static final Logger logger = LoggerFactory.getLogger( ExceptionUtil.class);
48
49
50
51         /**
52          * This error handling method maps an AAI Exception response to a
53          * WorkflowException Object.  It then sets the WorkflowException Object
54          * on the execution as "WorkflowException".
55          *
56          * This method formats the exception from AAI into the WorkflowException's
57          * errorMessage that CCD expects.
58          *
59          * @param execution the execution
60          * @param response the aai exception
61          */
62         WorkflowException MapAAIExceptionToWorkflowException(String response, DelegateExecution execution)
63         {
64                 def utils=new MsoUtils()
65                 def prefix=execution.getVariable("prefix")
66                 def errorMsg = execution.getVariable(prefix+"ErrorResponse")
67                 logger.trace("Begin MapAAIExceptionToWorkflowException ")
68                 String text = null
69                 def variables
70                 String errorCode = '5000'
71                 WorkflowException wfex
72                 logger.debug("response: " + response)
73                 try{
74                 try {
75                         //String msg = utils.getNodeXml(response, "Fault")
76                         variables = utils.getMultNodes(response, "variable")
77                         text = utils.getNodeText(response, "text")
78                 } catch (Exception ex) {
79                         //Ignore the exception - cases include non xml payload
80                         logger.debug("error mapping error, ignoring: " + ex)
81                 }
82
83                 if(text != null) {
84                         if(variables.size()>=4){
85                                 text = text.replaceFirst("%1", variables[0])
86                                 text = text.replaceFirst("%2", variables[1])
87                                 text = text.replaceFirst("%3", variables[2])
88                                 text = text.replaceFirst("%4", variables[3])
89                         }
90                         String modifiedErrorMessage = 'Received error from A&AI (' + text +')'
91                         logger.debug("ModifiedErrorMessage " + modifiedErrorMessage)
92                         // let $ModifiedErrorMessage := concat( 'Received error from A',$exceptionaai:ampersand,'AI (' ,functx:replace-multi($ErrorMessage,$from,$Variables ),')')
93                         buildWorkflowException(execution, 5000, modifiedErrorMessage)
94
95                         wfex = execution.getVariable("WorkflowException")
96                         logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), "Fault", "BPMN",
97                                         ErrorCode.UnknownError.getValue(), wfex.errorMessage);
98                         return wfex
99                 } else {
100                         try {
101                                 errorCode = MapErrorCode(errorMsg)
102                                 String mappedErrorMessage = MapErrorMessage(errorMsg, errorCode)
103
104                                 int errorCodeInt = Integer.parseInt(errorCode)
105                                 buildWorkflowException(execution, errorCodeInt, mappedErrorMessage)
106
107                                 logger.debug("mappedErrorMessage " + mappedErrorMessage)
108                                 wfex = execution.getVariable("WorkflowException")
109                                 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), "Fault", "BPMN",
110                                                 ErrorCode.UnknownError.getValue(), wfex.errorMessage);
111                                 return wfex
112                         } catch(Exception ex) {
113                                 logger.debug("error mapping error, return null: " + ex)
114                                 return null
115
116                         }
117                 }
118                 }catch(Exception e){
119                         logger.debug("Exception occured during MapAAIExceptionToWorkflowException: " + e)
120                         buildWorkflowException(execution, 5000, "Error mapping AAI Response to WorkflowException")
121                 }
122         }
123
124         /**
125          * This error handling method maps an AAI Exception response to a
126          * WorkflowException Object.  It then sets the WorkflowException Object
127          * on the execution as "WorkflowException".
128          *
129          * This method takes the exact exception inside the <Fault> tags from AAI Response
130          * and puts it into the WorkflowException's errorMessage.
131          *
132          * @param execution the execution
133          * @param response the aai exception
134          */
135         WorkflowException MapAAIExceptionToWorkflowExceptionGeneric(DelegateExecution execution, String response, int resCode){
136                 def utils=new MsoUtils()
137                 logger.debug("Start MapAAIExceptionToWorkflowExceptionGeneric Process")
138
139                 WorkflowException wfex
140                 try {
141                         if(utils.nodeExists(response, "Fault")){
142                                 String fault = utils.getNodeXml(response, "Fault")
143                                 fault = utils.removeXmlPreamble(fault)
144                                 fault = fault.replace("<Fault>", "").replace("</Fault>", "")
145                                 fault = fault.replaceAll("\\s+\\s+", "") // Removes extra white spaces
146                                 buildWorkflowException(execution, resCode, fault)
147                         }else if(utils.nodeExists(response, "RESTFault")){
148                                 String rFault = utils.getNodeXml(response, "RESTFault")
149                                 buildWorkflowException(execution, resCode, rFault)
150                         }else{
151                                 buildWorkflowException(execution, resCode, "Received a bad response from AAI")
152                         }
153                 } catch (Exception ex) {
154                         logger.debug("Exception Occured during MapAAIExceptionToWorkflowExceptionGeneric: " + ex)
155                         buildWorkflowException(execution, resCode, "Internal Error - Occured in MapAAIExceptionToWorkflowExceptionGeneric")
156
157                 }
158                 logger.debug("Outgoing WorkflowException is: " + execution.getVariable("WorkflowException"))
159                 logger.debug("Completed MapAAIExceptionToWorkflowExceptionGeneric Process")
160         }
161
162         /**
163          * This method takes a WorkflowException Object and builds
164          * WorkflowException Xml. This method should only be used
165          * for the purpose of sending a sync error response or for
166          * creating a FalloutHandler request.
167          *
168          *@param - WorkflowException Object
169          *
170          *@return - String WorkflowException Xml
171          *
172          *
173          */
174         String buildErrorResponseXml(WorkflowException wfex) {
175                 String xml
176                 if(wfex != null){
177                         String mes = XmlEscapers.xmlContentEscaper().escape(wfex.getErrorMessage())
178                         int code = wfex.getErrorCode()
179                         xml =
180                         """<aetgt:WorkflowException xmlns:aetgt="http://org.onap/so/workflow/schema/v1">
181                                         <aetgt:ErrorMessage>${MsoUtils.xmlEscape(mes)}</aetgt:ErrorMessage>
182                                         <aetgt:ErrorCode>${MsoUtils.xmlEscape(code)}</aetgt:ErrorCode>
183                                   </aetgt:WorkflowException>"""
184
185                 }else{
186                         xml =
187                         """<aetgt:WorkflowException xmlns:aetgt="http://org.onap/so/workflow/schema/v1">
188                                         <aetgt:ErrorMessage>Internal Error</aetgt:ErrorMessage>
189                                         <aetgt:ErrorCode>2500</aetgt:ErrorCode>
190                                   </aetgt:WorkflowException>"""
191                 }
192                 return xml
193         }
194
195         /*
196         5000    Received error from A&AI ($A&AI_ERROR)  Asynchronous    During orchestration of the recipe, A&AI returned an error. The error returned by A&AI is passed through in $A&AI_ERROR.
197         5010    Could not communicate with A&AI Asynchronous    During orchestration of the recipe, a connection with A&AI could not be established.
198         5020    No response from A&AI   Asynchronous    During orchestration of the recipe, communication was established with A&AI, but no response was received within the configured timeout.
199         */
200         /**
201          *
202          * Utility Method for MapAAIExceptionToWorkflowException
203          *
204          *@param - String ErrorMessage
205          *
206          *@return - String ErrorCode
207          *
208          */
209         private String MapErrorCode(String errorMessage)
210         {
211                 if(errorMessage==null){
212                         return '5000'
213                 }
214                 errorMessage = errorMessage.toLowerCase();
215                 if(errorMessage.contains('timed out') || errorMessage.contains('timeout'))
216                         return '5020'
217                 else if (errorMessage.contains('connection'))
218                         return '5010'
219                 else
220                         return '5000'
221         }
222
223         /**
224          *
225          * Utility Method for MapAAIExceptionToWorkflowException
226          *
227          *@param - String ErrorMessage
228          *@param - String ErrorCode
229          *
230          *@return - String ErrorMessage
231          *
232          */
233         private String MapErrorMessage(String errorMessage, String errorCode)
234         {
235                 if(errorMessage == null){
236                         errorMessage=""
237                 }
238                 if( errorCode.equals('5010')){
239                                         return 'Could not communicate with A&AI'
240                 }else if (errorCode.equals('5020')){
241                         return 'No response from A&AI'
242                 }else{
243                         return 'Received error from A&AI (' +errorMessage +')'
244                 }
245         }
246
247         /**
248          *
249          * Utility Method for Mapping SDNC
250          * Adapter Response Codes
251          *
252          *@param - String sdncResponseCode
253          *
254          *@return - String code
255          *
256          */
257         String MapSDNCResponseCodeToErrorCode(String sdncResponseCode)
258         {
259                 if (sdncResponseCode == '500') {
260                         return '5310'
261                 } else if ( sdncResponseCode == '408') {
262                          return '5320'
263                 } else if ( sdncResponseCode == '60010') {
264                          return '5350'
265                 } else {
266                    return '5300'
267                 }
268         }
269
270         /**
271          * This error handling method builds a WorkflowException Object.  It sets it on
272          * the execution as "WorkflowException".
273          *
274          * @param execution the execution
275          * @param errorCode the error code
276          * @param errorMessage the error message
277          */
278         public void buildWorkflowException(DelegateExecution execution, int errorCode, String errorMessage) {
279                 MsoUtils utils = new MsoUtils()
280                 String processKey = getProcessKey(execution);
281                 logger.debug("Building a WorkflowException for " + processKey)
282
283                 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage);
284                 execution.setVariable("WorkflowException", exception);
285                 logger.debug("Outgoing WorkflowException is " + exception)
286         }
287         
288         public void buildWorkflowException(DelegateExecution execution, int errorCode, String errorMessage, TargetEntities extSystemErrorSource) {
289                 MsoUtils utils = new MsoUtils()
290                 String processKey = getProcessKey(execution);
291                 logger.debug("Building a WorkflowException for " + processKey)
292
293                 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage, extSystemErrorSource);
294                 execution.setVariable("WorkflowException", exception);
295                 logger.debug("Outgoing WorkflowException is " + exception)
296         }
297
298         /**
299          * This error handling method builds a WorkflowException Object and throws a
300          * MSOWorkflowException.  It throws a "MSOWorkflowException" BpmnError after
301          * setting the WorkflowException Object on the execution as "WorkflowException".
302          *
303          * @param execution the execution
304          * @param errorCode the error code
305          * @param errorMessage the error message
306          */
307         public void buildAndThrowWorkflowException(DelegateExecution execution, int errorCode, String errorMessage) {
308                 String processKey = getProcessKey(execution);
309                 logger.debug("Building a WorkflowException for Subflow " + processKey)
310
311                 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage);
312                 execution.setVariable("WorkflowException", exception);
313                 logger.debug("Outgoing WorkflowException is " + exception)
314                 logger.debug("Throwing MSOWorkflowException")
315                 throw new BpmnError(errorCode.toString(), String.format("MSOWorkflowException: %s", errorMessage))
316         }
317
318         /**
319          * This method is executed after an MSOWorkflowException is caught by a
320          * subflow (during subflows "Error Handling Sub Process").
321          * It ensures the WorkflowException variable is populated before ending the
322          * subflow and also logs the subflows outgoing WorkflowException Variable.
323          *
324          * @param - execution
325          *
326          */
327         public void processSubflowsBPMNException(DelegateExecution execution){
328                 String processKey = getProcessKey(execution)
329                 try{
330                         logger.debug("Started ProcessSubflowsBPMNException Method")
331                         if(execution.getVariable("WorkflowException") == null){
332                                 buildWorkflowException(execution, 2500, "Internal Error - Occured During " + processKey)
333                         }
334
335                         logger.debug(processKey + " Outgoing WorkflowException is: " + execution.getVariable("WorkflowException"))
336                 }catch(Exception e){
337                         logger.debug("Caught Exception during ProcessSubflowsBPMNException Method: " + e)
338                 }
339                 logger.debug("Completed ProcessSubflowsBPMNException Method")
340         }
341
342         /**
343          * This method is executed after an MSOWorkflowException is caught by a
344          * Mainflow. It builds and returns a FalloutHandler Request. It also
345          * verifies the WorkflowException variable is populated.
346          *
347          * @param - execution
348          * @param - requestInfo
349          *
350          * @return - falloutHandlerRequest
351          *
352          */
353         public String processMainflowsBPMNException(DelegateExecution execution, String requestInfo){
354                 String processKey = getProcessKey(execution)
355                 try{
356                         logger.debug("Started ProcessMainflowBPMNException Method")
357                         if(execution.getVariable("WorkflowException") == null || isBlank(requestInfo)){
358                                 buildWorkflowException(execution, 2500, "Internal Error - WorkflowException Object and/or RequestInfo is null! " + processKey)
359                         }
360                         requestInfo = utils.removeXmlPreamble(requestInfo)
361                         WorkflowException wfex = execution.getVariable("WorkflowException")
362                         String errorMessage = XmlEscapers.xmlContentEscaper().escape(wfex.getErrorMessage())
363                         int errorCode = wfex.getErrorCode()
364
365                         String falloutHandlerRequest =
366                         """<aetgt:FalloutHandlerRequest xmlns:aetgt="http://org.onap/so/workflow/schema/v1"
367                                                                      xmlns:ns="http://org.onap/so/request/types/v1"
368                                                                      xmlns:wfsch="http://org.onap/so/workflow/schema/v1">
369                                            ${requestInfo}
370                                                 <aetgt:WorkflowException xmlns:aetgt="http://org.onap/so/workflow/schema/v1">
371                                                         <aetgt:ErrorMessage>${MsoUtils.xmlEscape(errorMessage)}</aetgt:ErrorMessage>
372                                                         <aetgt:ErrorCode>${MsoUtils.xmlEscape(errorCode)}</aetgt:ErrorCode>
373                                                 </aetgt:WorkflowException>
374                                         </aetgt:FalloutHandlerRequest>"""
375
376                         logger.debug(processKey + " Outgoing WorkflowException is: " + execution.getVariable("WorkflowException"))
377                         logger.debug(processKey + " Outgoing FalloutHandler Request is: " + falloutHandlerRequest)
378
379                         return falloutHandlerRequest
380
381                 }catch(Exception e){
382                         logger.debug("Caught Exception during ProcessMainflowBPMNException Method: " + e)
383                         return null
384                 }
385                 logger.debug("Completed ProcessMainflowBPMNException Method")
386         }
387
388         /**
389          *
390          * This method is executed after an Java Exception is caught
391          * It sets the WorkflowException variable. The method can be used in either mainflow or subflows.
392          *
393          * @param - execution
394          *
395          */
396         public void processJavaException(DelegateExecution execution){
397                 String processKey = getProcessKey(execution)
398                 try{
399                         logger.debug("Caught a Java Exception in " + processKey)
400                         logger.debug("Started processJavaException Method")
401                         // if the BPMN flow java error handler sets "BPMN_javaExpMsg", append it to the WFE
402                         String javaExpMsg = execution.getVariable("BPMN_javaExpMsg")
403             String errorMessage = execution.getVariable("gUnknownError")
404                         String wfeExpMsg = "Catch a Java Lang Exception in " + processKey
405                         if (javaExpMsg != null && !javaExpMsg.empty) {
406                                 wfeExpMsg = wfeExpMsg + ": " + javaExpMsg
407                         }
408             if (errorMessage != null && !errorMessage.empty) {
409                 logger.error("Unknown Error: " + errorMessage);
410             }
411             logger.error("Java Error: " + wfeExpMsg);
412                         buildWorkflowException(execution, 2500, wfeExpMsg)
413
414                 }catch(BpmnError b){
415             logger.error(b);
416                         throw b
417                 }catch(Exception e){
418             logger.error(e);
419                         logger.debug("Caught Exception during processJavaException Method: " + e)
420                         buildWorkflowException(execution, 2500, "Internal Error - During Process Java Exception")
421                 }
422                 logger.debug("Completed processJavaException Method")
423         }
424
425
426         public void preProcessRequest(DelegateExecution execution) {
427                 // TODO Auto-generated method stub
428
429         }
430         
431         public String getErrorMessage(WorkflowException wfe, String processKey) {
432                 if(wfe == null) {
433                         return "Unexpected error encountered in " + processKey
434                 }
435                 else {
436                         return wfe.getErrorMessage()
437                 }
438         }
439         
440         public int getErrorCode(WorkflowException wfe) {
441                 if(wfe == null) {
442                         return 2500
443                 }
444                 else {
445                         return wfe.getErrorCode()
446                 }
447         }
448 }