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