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