2 * ============LICENSE_START=======================================================
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
23 package org.onap.so.bpmn.common.scripts
25 import org.onap.so.logger.LoggingAnchor
26 import org.onap.so.logger.ErrorCode
28 import static org.apache.commons.lang3.StringUtils.*
30 import com.google.common.xml.XmlEscapers
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
46 class ExceptionUtil extends AbstractServiceTaskProcessor {
47 private static final Logger logger = LoggerFactory.getLogger( ExceptionUtil.class);
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".
56 * This method formats the exception from AAI into the WorkflowException's
57 * errorMessage that CCD expects.
59 * @param execution the execution
60 * @param response the aai exception
62 WorkflowException MapAAIExceptionToWorkflowException(String response, DelegateExecution execution)
64 def utils=new MsoUtils()
65 def prefix=execution.getVariable("prefix")
66 def errorMsg = execution.getVariable(prefix+"ErrorResponse")
67 logger.trace("Begin MapAAIExceptionToWorkflowException ")
70 String errorCode = '5000'
71 WorkflowException wfex
72 logger.debug("response: " + response)
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)
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])
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)
95 wfex = execution.getVariable("WorkflowException")
96 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), "Fault", "BPMN",
97 ErrorCode.UnknownError.getValue(), wfex.errorMessage);
101 errorCode = MapErrorCode(errorMsg)
102 String mappedErrorMessage = MapErrorMessage(errorMsg, errorCode)
104 int errorCodeInt = Integer.parseInt(errorCode)
105 buildWorkflowException(execution, errorCodeInt, mappedErrorMessage)
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);
112 } catch(Exception ex) {
113 logger.debug("error mapping error, return null: " + ex)
119 logger.debug("Exception occured during MapAAIExceptionToWorkflowException: " + e)
120 buildWorkflowException(execution, 5000, "Error mapping AAI Response to WorkflowException")
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".
129 * This method takes the exact exception inside the <Fault> tags from AAI Response
130 * and puts it into the WorkflowException's errorMessage.
132 * @param execution the execution
133 * @param response the aai exception
135 WorkflowException MapAAIExceptionToWorkflowExceptionGeneric(DelegateExecution execution, String response, int resCode){
136 def utils=new MsoUtils()
137 logger.debug("Start MapAAIExceptionToWorkflowExceptionGeneric Process")
139 WorkflowException wfex
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)
151 buildWorkflowException(execution, resCode, "Received a bad response from AAI")
153 } catch (Exception ex) {
154 logger.debug("Exception Occured during MapAAIExceptionToWorkflowExceptionGeneric: " + ex)
155 buildWorkflowException(execution, resCode, "Internal Error - Occured in MapAAIExceptionToWorkflowExceptionGeneric")
158 logger.debug("Outgoing WorkflowException is: " + execution.getVariable("WorkflowException"))
159 logger.debug("Completed MapAAIExceptionToWorkflowExceptionGeneric Process")
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.
168 *@param - WorkflowException Object
170 *@return - String WorkflowException Xml
174 String buildErrorResponseXml(WorkflowException wfex) {
177 String mes = XmlEscapers.xmlContentEscaper().escape(wfex.getErrorMessage())
178 int code = wfex.getErrorCode()
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>"""
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>"""
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.
202 * Utility Method for MapAAIExceptionToWorkflowException
204 *@param - String ErrorMessage
206 *@return - String ErrorCode
209 private String MapErrorCode(String errorMessage)
211 if(errorMessage==null){
214 errorMessage = errorMessage.toLowerCase();
215 if(errorMessage.contains('timed out') || errorMessage.contains('timeout'))
217 else if (errorMessage.contains('connection'))
225 * Utility Method for MapAAIExceptionToWorkflowException
227 *@param - String ErrorMessage
228 *@param - String ErrorCode
230 *@return - String ErrorMessage
233 private String MapErrorMessage(String errorMessage, String errorCode)
235 if(errorMessage == null){
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'
243 return 'Received error from A&AI (' +errorMessage +')'
249 * Utility Method for Mapping SDNC
250 * Adapter Response Codes
252 *@param - String sdncResponseCode
254 *@return - String code
257 String MapSDNCResponseCodeToErrorCode(String sdncResponseCode)
259 if (sdncResponseCode == '500') {
261 } else if ( sdncResponseCode == '408') {
263 } else if ( sdncResponseCode == '60010') {
271 * This error handling method builds a WorkflowException Object. It sets it on
272 * the execution as "WorkflowException".
274 * @param execution the execution
275 * @param errorCode the error code
276 * @param errorMessage the error message
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)
283 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage);
284 execution.setVariable("WorkflowException", exception);
285 logger.debug("Outgoing WorkflowException is " + exception)
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)
293 WorkflowException exception = new WorkflowException(processKey, errorCode, errorMessage, extSystemErrorSource);
294 execution.setVariable("WorkflowException", exception);
295 logger.debug("Outgoing WorkflowException is " + exception)
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".
303 * @param execution the execution
304 * @param errorCode the error code
305 * @param errorMessage the error message
307 public void buildAndThrowWorkflowException(DelegateExecution execution, int errorCode, String errorMessage) {
308 String processKey = getProcessKey(execution);
309 logger.debug("Building a WorkflowException for Subflow " + processKey)
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))
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.
327 public void processSubflowsBPMNException(DelegateExecution execution){
328 String processKey = getProcessKey(execution)
330 logger.debug("Started ProcessSubflowsBPMNException Method")
331 if(execution.getVariable("WorkflowException") == null){
332 buildWorkflowException(execution, 2500, "Internal Error - Occured During " + processKey)
335 logger.debug(processKey + " Outgoing WorkflowException is: " + execution.getVariable("WorkflowException"))
337 logger.debug("Caught Exception during ProcessSubflowsBPMNException Method: " + e)
339 logger.debug("Completed ProcessSubflowsBPMNException Method")
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.
348 * @param - requestInfo
350 * @return - falloutHandlerRequest
353 public String processMainflowsBPMNException(DelegateExecution execution, String requestInfo){
354 String processKey = getProcessKey(execution)
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)
360 requestInfo = utils.removeXmlPreamble(requestInfo)
361 WorkflowException wfex = execution.getVariable("WorkflowException")
362 String errorMessage = XmlEscapers.xmlContentEscaper().escape(wfex.getErrorMessage())
363 int errorCode = wfex.getErrorCode()
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">
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>"""
376 logger.debug(processKey + " Outgoing WorkflowException is: " + execution.getVariable("WorkflowException"))
377 logger.debug(processKey + " Outgoing FalloutHandler Request is: " + falloutHandlerRequest)
379 return falloutHandlerRequest
382 logger.debug("Caught Exception during ProcessMainflowBPMNException Method: " + e)
385 logger.debug("Completed ProcessMainflowBPMNException Method")
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.
396 public void processJavaException(DelegateExecution execution){
397 String processKey = getProcessKey(execution)
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
408 if (errorMessage != null && !errorMessage.empty) {
409 logger.error("Unknown Error: " + errorMessage);
411 logger.error("Java Error: " + wfeExpMsg);
412 buildWorkflowException(execution, 2500, wfeExpMsg)
419 logger.debug("Caught Exception during processJavaException Method: " + e)
420 buildWorkflowException(execution, 2500, "Internal Error - During Process Java Exception")
422 logger.debug("Completed processJavaException Method")
426 public void preProcessRequest(DelegateExecution execution) {
427 // TODO Auto-generated method stub
431 public String getErrorMessage(WorkflowException wfe, String processKey) {
433 return "Unexpected error encountered in " + processKey
436 return wfe.getErrorMessage()
440 public int getErrorCode(WorkflowException wfe) {
445 return wfe.getErrorCode()