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