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.camunda.bpm.engine.delegate.BpmnError
 
  26 import org.camunda.bpm.engine.delegate.DelegateExecution
 
  27 import org.camunda.bpm.engine.variable.VariableMap
 
  28 import org.camunda.bpm.engine.variable.Variables
 
  29 import org.camunda.bpm.engine.variable.Variables.SerializationDataFormats
 
  30 import org.camunda.bpm.engine.variable.impl.value.ObjectValueImpl
 
  31 import org.onap.so.bpmn.common.workflow.context.WorkflowCallbackResponse
 
  32 import org.onap.so.bpmn.common.workflow.context.WorkflowContextHolder
 
  33 import org.onap.so.bpmn.core.UrnPropertiesReader
 
  34 import org.onap.so.bpmn.core.WorkflowException
 
  35 import org.onap.so.client.aai.AAIResourcesClient
 
  36 import org.springframework.web.util.UriUtils
 
  37 import org.slf4j.Logger
 
  38 import org.slf4j.LoggerFactory
 
  40 import groovy.json.JsonSlurper
 
  42 public abstract class AbstractServiceTaskProcessor implements ServiceTaskProcessor {
 
  43         private static final Logger logger = LoggerFactory.getLogger( MsoUtils.class);
 
  45         public MsoUtils utils = new MsoUtils()
 
  48          * Logs a WorkflowException at the ERROR level with the specified message.
 
  49          * @param execution the execution
 
  51         public void logWorkflowException(DelegateExecution execution, String message) {
 
  52                 def workflowException = execution.getVariable("WorkflowException")
 
  54                 if (workflowException == null) {
 
  55                         logger.error(message);
 
  57                         logger.error('{}: {}', message, workflowException)
 
  62          * Saves the WorkflowException in the execution to the specified variable,
 
  63          * clearing the WorkflowException variable so the workflow can continue
 
  64          * processing (perhaps catching another WorkflowException).
 
  65          * @param execution the execution
 
  66          * @return the name of the destination variable
 
  68         public saveWorkflowException(DelegateExecution execution, String variable) {
 
  69                 if (variable == null) {
 
  70                         throw new NullPointerException();
 
  73                 execution.setVariable(variable, execution.getVariable("WorkflowException"))
 
  74                 execution.setVariable("WorkflowException", null)
 
  79          * Validates that the request exists and that the mso-request-id variable is set.
 
  80          * Additional required variables may be checked by specifying their names.
 
  81          * NOTE: services requiring mso-service-instance-id must specify it explicitly!
 
  82          * If a problem is found, buildAndThrowWorkflowException builds a WorkflowException
 
  83          * and throws an MSOWorkflowException.  This method also sets up the log context for
 
  86          * @param execution the execution
 
  87          * @return the validated request
 
  89         public String validateRequest(DelegateExecution execution, String... requiredVariables) {
 
  90                 ExceptionUtil exceptionUtil = new ExceptionUtil()
 
  91                 def method = getClass().getSimpleName() + '.validateRequest(' +
 
  92                         'execution=' + execution.getId() +
 
  93                         ', requredVariables=' + requiredVariables +
 
  95                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
  96                 logger.debug('Entered ' + method)
 
  98                 String processKey = getProcessKey(execution)
 
  99                 def prefix = execution.getVariable("prefix")
 
 101                 if (prefix == null) {
 
 102                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, processKey + " prefix is null")
 
 106                         def request = execution.getVariable(prefix + 'Request')
 
 108                         if (request == null) {
 
 109                                 request = execution.getVariable(processKey + 'Request')
 
 111                                 if (request == null) {
 
 112                                         request = execution.getVariable('bpmnRequest')
 
 115                                 setVariable(execution, processKey + 'Request', null)
 
 116                                 setVariable(execution, 'bpmnRequest', null)
 
 117                                 setVariable(execution, prefix + 'Request', request)
 
 120                         if (request == null) {
 
 121                                 exceptionUtil.buildAndThrowWorkflowException(execution, 1002, processKey + " request is null")
 
 124                         // All requests must have a request ID.
 
 125                         // Some requests (e.g. SDN-MOBILITY) do not have a service instance ID.
 
 127                         String requestId = null
 
 128                         String serviceInstanceId = null
 
 130                         List<String> allRequiredVariables = new ArrayList<String>()
 
 131                         allRequiredVariables.add("mso-request-id")
 
 133                         if (requiredVariables != null) {
 
 134                                 for (String variable : requiredVariables) {
 
 135                                         if (!allRequiredVariables.contains(variable)) {
 
 136                                                 allRequiredVariables.add(variable)
 
 141                         for (String variable : allRequiredVariables) {
 
 142                                 def value = execution.getVariable(variable)
 
 143                                 if (value == null || ((value instanceof CharSequence) && value.length() == 0)) {
 
 144                                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, processKey +
 
 145                                                 " request was received with no '" + variable + "' variable")
 
 148                                 if ("mso-request-id".equals(variable)) {
 
 149                                         requestId = (String) value
 
 150                                 } else if ("mso-service-instance-id".equals(variable)) {
 
 151                                         serviceInstanceId = (String) value
 
 155                         if (serviceInstanceId == null) {
 
 156                                 serviceInstanceId = (String) execution.getVariable("mso-service-instance-id")
 
 159                         logger.debug('Incoming message: ' + System.lineSeparator() + request)
 
 160                         logger.debug('Exited ' + method)
 
 162                 } catch (BpmnError e) {
 
 164                 } catch (Exception e) {
 
 165                         logger.error('Caught exception in {}: {}', method, e.getMessage(), e)
 
 166                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, "Invalid Message")
 
 171          * gets vars stored in a JSON object in prefix+Request and returns as a LazyMap
 
 172          * setting log context here too
 
 173          * @param execution the execution
 
 174          * @return the inputVars
 
 176         public Map validateJSONReq(DelegateExecution execution) {
 
 177                 def method = getClass().getSimpleName() + '.validateJSONReq(' +
 
 178                                 'execution=' + execution.getId() +
 
 180                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
 181                 logger.debug('Entered ' + method)
 
 183                 String processKey = getProcessKey(execution);
 
 184                 def prefix = execution.getVariable("prefix")
 
 186                 def request = getVariable(execution, prefix + 'Request')
 
 188                 if (request == null) {
 
 189                         request = getVariable(execution, processKey + 'Request')
 
 191                         if (request == null) {
 
 192                                 request = getVariable(execution, 'bpmnRequest')
 
 194                         execution.setVariable(prefix + 'Request', request)
 
 197                 def jsonSlurper = new JsonSlurper()
 
 198                 def parsed = jsonSlurper.parseText(request)
 
 201                 logger.debug('Incoming message: ' + System.lineSeparator() + request)
 
 202                 logger.debug('Exited ' + method)
 
 208          * Sends a response to the workflow service that invoked the process.  This method
 
 209          * may only be used by top-level processes that were directly invoked by the
 
 210          * asynchronous workflow service.
 
 211          * @param execution the execution
 
 212          * @param responseCode the response code
 
 213          * @param content the message content
 
 214          * @throws IllegalArgumentException if the response code is invalid
 
 216          * @throws UnsupportedOperationException if not invoked by an asynchronous,
 
 218          * @throws IllegalStateException if a response has already been sent
 
 220         protected void sendWorkflowResponse(DelegateExecution execution, Object responseCode, String response) {
 
 221                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
 223                         String processKey = getProcessKey(execution);
 
 225                         // isAsyncProcess is injected by the workflow service that started the flow
 
 226                         if (!String.valueOf(execution.getVariable("isAsyncProcess")).equals("true")) {
 
 227                                 throw new UnsupportedOperationException(processKey + ": " +
 
 228                                         "sendWorkflowResponse is valid only in asynchronous workflows");
 
 231                         if (String.valueOf(execution.getVariable(processKey + "WorkflowResponseSent")).equals("true")) {
 
 232                                         logger.debug("Sync response has already been sent for " + processKey)
 
 235                                 logger.debug("Building " + processKey + " response ")
 
 240                                         intResponseCode = Integer.parseInt(String.valueOf(responseCode));
 
 242                                         if (intResponseCode < 100 || intResponseCode > 599) {
 
 243                                                 throw new NumberFormatException(String.valueOf(responseCode));
 
 245                                 } catch (NumberFormatException e) {
 
 246                                         throw new IllegalArgumentException("Process " + processKey
 
 247                                                 + " provided an invalid HTTP response code: " + responseCode);
 
 250                                 // Only 2XX responses are considered "Success"
 
 251                                 String status = (intResponseCode >= 200 && intResponseCode <= 299) ?
 
 254                                 // TODO: Should deprecate use of processKey+Response variable for the response. Will use "WorkflowResponse" instead
 
 255                                 execution.setVariable(processKey + "ResponseCode", String.valueOf(intResponseCode))
 
 256                                 execution.setVariable(processKey + "Response", response);
 
 257                                 execution.setVariable(processKey + "Status", status);
 
 258                                 execution.setVariable("WorkflowResponse", response)
 
 260                                 logger.debug("Sending response for " + processKey
 
 261                                         + " ResponseCode=" + intResponseCode
 
 262                                         + " Status=" + status
 
 263                                         + " Response=\n" + response)
 
 265                                 // TODO: ensure that this flow was invoked asynchronously?
 
 267                                 WorkflowCallbackResponse callbackResponse = new WorkflowCallbackResponse()
 
 268                                 callbackResponse.setStatusCode(intResponseCode)
 
 269                                 callbackResponse.setMessage(status)
 
 270                                 callbackResponse.setResponse(response)
 
 272                                 // TODO: send this data with HTTP POST
 
 274                                 WorkflowContextHolder.getInstance().processCallback(
 
 276                                         execution.getProcessInstanceId(),
 
 277                                         execution.getVariable("mso-request-id"),
 
 280                                 execution.setVariable(processKey + "WorkflowResponseSent", "true");
 
 283                 } catch (Exception ex) {
 
 284                         logger.error("Unable to send workflow response to client ....", ex)
 
 289          * Returns true if a workflow response has already been sent.
 
 290          * @param execution the execution
 
 292         protected boolean isWorkflowResponseSent(DelegateExecution execution) {
 
 293                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
 294                 String processKey = getProcessKey(execution);
 
 295                 return String.valueOf(execution.getVariable(processKey + "WorkflowResponseSent")).equals("true");
 
 299          * Returns the process definition key (i.e. the process name) of the
 
 302          * @param execution the execution
 
 304         public String getProcessKey(DelegateExecution execution) {
 
 305                 def testKey = execution.getVariable("testProcessKey")
 
 309                 return execution.getProcessEngineServices().getRepositoryService()
 
 310                         .getProcessDefinition(execution.getProcessDefinitionId()).getKey()
 
 314          * Returns the process definition key (i.e. the process name) of the
 
 316          * @param execution the execution
 
 318         public String getMainProcessKey(DelegateExecution execution) {
 
 319                 DelegateExecution exec = execution
 
 322                         DelegateExecution parent = exec.getSuperExecution()
 
 324                         if (parent == null) {
 
 325                                 parent = exec.getParent()
 
 327                                 if (parent == null) {
 
 335                 return execution.getProcessEngineServices().getRepositoryService()
 
 336                         .getProcessDefinition(exec.getProcessDefinitionId()).getKey()
 
 340          * Gets the node for the named element from the given xml. If the element
 
 341          * does not exist in the xml or is empty, a WorkflowException is created
 
 342          * (and as a result, a MSOWorkflowException event is thrown).
 
 344          * @param execution The flow's execution.
 
 345          * @param xml Xml to search.
 
 346          * @param elementName Name of element to search for.
 
 347          * @return The element node, if found in the xml.
 
 349         protected String getRequiredNodeXml(DelegateExecution execution, String xml, String elementName) {
 
 350                 ExceptionUtil exceptionUtil = new ExceptionUtil()
 
 351                 def element = utils.getNodeXml(xml, elementName, false)
 
 352                 if (element.trim().isEmpty()) {
 
 353                         def msg = 'Required element \'' + elementName + '\' is missing or empty'
 
 355                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
 
 362          * Gets the value of the named element from the given xml. If the element
 
 363          * does not exist in the xml or is empty, a WorkflowException is created
 
 364          * (and as a result, a MSOWorkflowException event is thrown).
 
 366          * @param execution The flow's execution.
 
 367          * @param xml Xml to search.
 
 368          * @param elementName Name of element to whose value to get.
 
 369          * @return The non-empty value of the element, if found in the xml.
 
 371         protected String getRequiredNodeText(DelegateExecution execution, String xml, String elementName) {
 
 372                 ExceptionUtil exceptionUtil = new ExceptionUtil()
 
 373                 def elementText = utils.getNodeText(xml, elementName)
 
 374                 if ((elementText == null) || (elementText.isEmpty())) {
 
 375                         def msg = 'Required element \'' + elementName + '\' is missing or empty'
 
 377                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000, msg)
 
 384          * Get the text for the specified element from the specified xml.  If
 
 385          * the element does not exist, return the specified default value.
 
 387          * @param xml Xml from which to get the element's text
 
 388          * @param elementName Name of element whose text to get
 
 389          * @param defaultValue the default value
 
 390          * @return the element's text or the default value if the element does not
 
 391          * exist in the given xml
 
 393         protected String getNodeText(String xml, String elementName, String defaultValue) {
 
 394                 def nodeText = utils.getNodeText(xml, elementName)
 
 395                 return (nodeText == null) ? defaultValue : nodeText
 
 399          * Get the text for the specified element from the specified xml.  If
 
 400          * the element does not exist, return an empty string.
 
 402          * @param xml Xml from which to get the element's text.
 
 403          * @param elementName Name of element whose text to get.
 
 404          * @return the element's text or an empty string if the element does not
 
 405          * exist in the given xml.
 
 407         protected String getNodeTextForce(String xml, String elementName) {
 
 408                 return getNodeText(xml, elementName, '');
 
 412         *Store the variable as typed with java serialization type
 
 417         public void setVariable(DelegateExecution execution, String name, Object value) {
 
 418                 VariableMap variables = Variables.createVariables()
 
 419                 variables.putValueTyped('payload', Variables.objectValue(value)
 
 420                 .serializationDataFormat(SerializationDataFormats.JAVA) // tells the engine to use java serialization for persisting the value
 
 422                 execution.setVariable(name,variables)
 
 425         //TODO not sure how this will look in Cockpit
 
 428          * Returns the variable map
 
 433         public static String getVariable(DelegateExecution execution, String name) {
 
 434                 def myObj = execution.getVariable(name)
 
 435                 if(myObj instanceof VariableMap){
 
 436                         VariableMap serializedObjectMap = (VariableMap) myObj
 
 437                         ObjectValueImpl payloadObj = serializedObjectMap.getValueTyped('payload')
 
 438                         return payloadObj.getValue()
 
 446          * Returns true if a value equals one of the provided set. Equality is
 
 447          * determined by using the equals method if the value object and the
 
 448          * object in the provided set have the same class. Otherwise, the objects
 
 449          * are converted to strings and then compared.  Nulls are permitted for
 
 450          * the value as well as in the provided set
 
 453          *     def statusCode = getStatusCode()
 
 454          *     isOneOf(statusCode, 200, 201, 204)
 
 456          * @param value the value to test
 
 457          * @param these a set of permissable values
 
 458          * @return true if the value is in the provided set
 
 460         public boolean isOneOf(Object value, Object... these) {
 
 461                 for (Object thisOne : these) {
 
 462                         if (thisOne == null) {
 
 468                                         if (value.getClass() == thisOne.getClass()) {
 
 469                                                 if (value.equals(thisOne)) {
 
 473                                                 if (String.valueOf(value).equals(String.valueOf(thisOne))) {
 
 484          * Sets flows success indicator variable.
 
 487         public void setSuccessIndicator(DelegateExecution execution, boolean isSuccess) {
 
 488                 String prefix = execution.getVariable('prefix')
 
 489                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
 491                 logger.debug('Entered SetSuccessIndicator Method')
 
 492                 execution.setVariable(prefix+'SuccessIndicator', isSuccess)
 
 493                 logger.debug('Outgoing SuccessIndicator is: ' + execution.getVariable(prefix+'SuccessIndicator') + '')
 
 497          * Sends a Error Sync Response
 
 500         public void sendSyncError(DelegateExecution execution) {
 
 501                 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
 502                 String requestId = execution.getVariable("mso-request-id")
 
 503                 logger.debug('sendSyncError, requestId: ' + requestId)
 
 504                 WorkflowException workflowExceptionObj = execution.getVariable("WorkflowException")
 
 505                 if (workflowExceptionObj != null) {
 
 506                         String errorMessage = workflowExceptionObj.getErrorMessage()
 
 507                         def errorCode = workflowExceptionObj.getErrorCode()
 
 508                         logger.debug('sendSyncError, requestId: '  + requestId + ' | errorMessage: ' + errorMessage + ' | errorCode: ' + errorCode)
 
 509                         sendWorkflowResponse(execution, errorCode, errorMessage)
 
 514          * Executes a named groovy script method in the current object
 
 516         public void executeMethod(String methodName, Object... args) {
 
 518                 if (args != null && args.size() > 0) {
 
 520                         // First argument of method to call is always the execution object
 
 521                         DelegateExecution execution = (DelegateExecution) args[0]
 
 523                         def classAndMethod = getClass().getSimpleName() + '.' + methodName + '(execution=' + execution.getId() + ')'
 
 524                         def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
 
 526                         logger.debug('Entered ' + classAndMethod)
 
 527                         logger.debug('Received parameters: ' + args)
 
 530                                 def methodToCall = this.metaClass.getMetaMethod(methodName, args)
 
 531                                 logger.debug('Method to call: ' + methodToCall)
 
 532                                 methodToCall?.invoke(this, args)
 
 534                         catch(BpmnError bpmnError) {
 
 535                                 logger.debug('Rethrowing BpmnError ' + bpmnError.getMessage())
 
 539                                 logger.debug('Unexpected error encountered - {}', e.getMessage(), e)
 
 540                                 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
 
 543                                 logger.debug('Exited ' + classAndMethod)
 
 549          *This method determines and adds the appropriate ending to come
 
 550          *after a number (-st, -nd, -rd, or -th)
 
 554          *@return String ending - number with suffix
 
 556         public static String labelMaker(Object n) {
 
 558                 if(n instanceof String){
 
 559                         num = Integer.parseInt(n)
 
 564                 String ending = ""; //the end to be added to the number
 
 566                 if ((num % 10 == 1) && (num != 11)) {
 
 568                         } else if ((num % 10 == 2) && (num != 12)) {
 
 570                         } else if ((num % 10 == 3) && (num != 13)) {
 
 580          * Constructs a workflow message callback URL for the specified message type and correlator.
 
 581          * This type of callback URL is used when a workflow wants an MSO adapter (like the SDNC
 
 582          * adapter) to call it back.  In other words, this is for callbacks internal to the MSO
 
 583          * complex.  Use <code>createWorkflowMessageAdapterCallbackURL</code> if the callback
 
 584          * will come from outside the MSO complex.
 
 585          * @param messageType the message type (e.g. SDNCAResponse or VNFAResponse)
 
 586          * @param correlator the correlator value (e.g. a request ID)
 
 588         public String createCallbackURL(DelegateExecution execution, String messageType, String correlator) {
 
 589                 String endpoint = UrnPropertiesReader.getVariable("mso.workflow.message.endpoint", execution)
 
 591                 if (endpoint == null || endpoint.isEmpty()) {
 
 592                         ExceptionUtil exceptionUtil = new ExceptionUtil()
 
 593                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000,
 
 594                                 'mso:workflow:message:endpoint URN mapping is not set')
 
 597                 while (endpoint.endsWith('/')) {
 
 598                         endpoint = endpoint.substring(0, endpoint.length()-1)
 
 602                         '/' + UriUtils.encodePathSegment(messageType, 'UTF-8') +
 
 603                         '/' + UriUtils.encodePathSegment(correlator, 'UTF-8')
 
 608          * Constructs a workflow message callback URL for the specified message type and correlator.
 
 609          * This type of callback URL is used when a workflow wants a system outside the MSO complex
 
 610          * to call it back through the Workflow Message Adapter.
 
 611          * @param messageType the message type (e.g. SNIROResponse)
 
 612          * @param correlator the correlator value (e.g. a request ID)
 
 614         public String createWorkflowMessageAdapterCallbackURL(DelegateExecution execution, String messageType, String correlator) {
 
 615                 String endpoint = UrnPropertiesReader.getVariable("mso.adapters.workflow.message.endpoint", execution)
 
 617                 if (endpoint == null || endpoint.isEmpty()) {
 
 618                         ExceptionUtil exceptionUtil = new ExceptionUtil()
 
 619                         exceptionUtil.buildAndThrowWorkflowException(execution, 2000,
 
 620                                 'mso:adapters:workflow:message:endpoint URN mapping is not set')
 
 623                 while (endpoint.endsWith('/')) {
 
 624                         endpoint = endpoint.substring(0, endpoint.length()-1)
 
 628                         '/' + UriUtils.encodePathSegment(messageType, 'UTF-8') +
 
 629                         '/' + UriUtils.encodePathSegment(correlator, 'UTF-8')
 
 632         public void setRollbackEnabled(DelegateExecution execution, isDebugLogEnabled) {
 
 635                 def prefix = execution.getVariable('prefix')
 
 636                 def disableRollback = execution.getVariable("disableRollback")
 
 637                 def defaultRollback = UrnPropertiesReader.getVariable("mso.rollback", execution).toBoolean()
 
 639                 logger.debug('disableRollback: ' + disableRollback)
 
 640                 logger.debug('defaultRollback: ' + defaultRollback)
 
 644                 if(disableRollback == null || disableRollback == '' ) {
 
 645                         // get from default urn settings for mso_rollback
 
 646                         disableRollback = !defaultRollback
 
 647                         rollbackEnabled = defaultRollback
 
 648                         logger.debug('disableRollback is null or empty!')
 
 651                         if(disableRollback == true) {
 
 652                                 rollbackEnabled = false
 
 654                         else if(disableRollback == false){
 
 655                                 rollbackEnabled = true
 
 658                                 rollbackEnabled = defaultRollback
 
 662                 execution.setVariable(prefix+"backoutOnFailure", rollbackEnabled)
 
 663                 logger.debug('rollbackEnabled (aka backoutOnFailure): ' + rollbackEnabled)
 
 666         public void setBasicDBAuthHeader(DelegateExecution execution, isDebugLogEnabled) {
 
 668                         String basicAuthValueDB = UrnPropertiesReader.getVariable("mso.adapters.db.auth", execution)
 
 669                         def encodedString = utils.getBasicAuth(basicAuthValueDB, UrnPropertiesReader.getVariable("mso.msoKey", execution))
 
 670                         execution.setVariable("BasicAuthHeaderValueDB",encodedString)
 
 671                 } catch (IOException ex) {
 
 672                         String dataErrorMessage = " Unable to encode Catalog DB user/password string - " + ex.getMessage()
 
 673                         logger.debug(dataErrorMessage)
 
 674                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 2500, dataErrorMessage)
 
 677     public AAIResourcesClient getAAIClient(){
 
 678         return  new AAIResourcesClient();