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.infrastructure.scripts
25 import static org.apache.cxf.common.util.CollectionUtils.isEmpty
26 import javax.ws.rs.core.UriBuilder
27 import org.camunda.bpm.engine.delegate.BpmnError
28 import org.camunda.bpm.engine.delegate.DelegateExecution
29 import org.onap.aai.domain.yang.GenericVnf
30 import org.onap.aai.domain.yang.VfModule
31 import org.onap.aai.domain.yang.VolumeGroup
32 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper
33 import org.onap.aaiclient.client.aai.entities.Relationships
34 import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri
35 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory
36 import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder
37 import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder.Types
38 import org.onap.logging.filter.base.ErrorCode
39 import org.onap.so.bpmn.common.scripts.ExceptionUtil
40 import org.onap.so.bpmn.common.scripts.MsoUtils
41 import org.onap.so.bpmn.common.scripts.VfModuleBase
42 import org.onap.so.bpmn.common.scripts.VidUtils
43 import org.onap.so.bpmn.core.UrnPropertiesReader
44 import org.onap.so.bpmn.core.WorkflowException
45 import org.onap.so.constants.Defaults
46 import org.onap.so.logger.LoggingAnchor
47 import org.onap.so.logger.MessageEnum
48 import org.slf4j.Logger
49 import org.slf4j.LoggerFactory
50 import groovy.json.JsonException
51 import groovy.json.JsonSlurper
53 class UpdateVfModuleVolumeInfraV1 extends VfModuleBase {
54 private static final Logger logger = LoggerFactory.getLogger(UpdateVfModuleVolumeInfraV1.class)
55 private ExceptionUtil exceptionUtil = new ExceptionUtil()
58 * Initialize the flow's variables.
60 * @param execution The flow's execution instance.
62 private void initProcessVariables(DelegateExecution execution) {
63 execution.setVariable('prefix', 'UPDVfModVol_')
64 execution.setVariable('UPDVfModVol_Request', null)
65 execution.setVariable('UPDVfModVol_requestInfo', null)
66 execution.setVariable('UPDVfModVol_requestId', null)
67 execution.setVariable('UPDVfModVol_source', null)
68 execution.setVariable('UPDVfModVol_volumeInputs', null)
69 execution.setVariable('UPDVfModVol_volumeGroupId', null)
70 execution.setVariable('UPDVfModVol_vnfType', null)
71 execution.setVariable('UPDVfModVol_serviceId', null)
72 execution.setVariable('UPDVfModVol_aicCloudRegion', null)
73 execution.setVariable('UPDVfModVol_tenantId', null)
74 execution.setVariable('UPDVfModVol_volumeParams', null)
75 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', null)
76 execution.setVariable('UPDVfModVol_volumeGroupTenantId', null)
77 execution.setVariable('UpdateVfModuleVolumeSuccessIndicator', false)
81 * Perform initial processing, such as request validation, initialization of variables, etc.
84 public void preProcessRequest(DelegateExecution execution) {
85 def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
86 preProcessRequest(execution, isDebugEnabled)
89 public void preProcessRequest(DelegateExecution execution, isDebugLogEnabled) {
91 initProcessVariables(execution)
92 String jsonRequest = validateRequest(execution)
97 def jsonSlurper = new JsonSlurper()
98 Map reqMap = jsonSlurper.parseText(jsonRequest)
100 def serviceInstanceId = execution.getVariable('serviceInstanceId')
101 def volumeGroupId = execution.getVariable('volumeGroupId')
102 //def vnfId = execution.getVariable('vnfId')
104 def vidUtils = new VidUtils(this)
105 request = vidUtils.createXmlVolumeRequest(reqMap, 'UPDATE_VF_MODULE_VOL', serviceInstanceId, volumeGroupId)
107 execution.setVariable('UPDVfModVol_Request', request)
108 execution.setVariable("UPDVfModVol_isVidRequest", true)
110 //need to get persona-model-id aka model-invariantId to use later to validate vf-module relation in AAI
112 def modelInvariantId = reqMap.requestDetails.modelInfo.modelInvariantUuid ?: ''
113 execution.setVariable('UPDVfModVol_modelInvariantId', modelInvariantId)
115 logger.debug("modelInvariantId from request: {}", modelInvariantId)
116 logger.debug("XML request:\n{}", request)
118 catch (JsonException je) {
119 logger.debug(" Request is in XML format.")
120 // assume request is in XML format - proceed as usual to process XML request
123 def requestId = execution.getVariable('mso-request-id')
125 def requestInfo = getRequiredNodeXml(execution, request, 'request-info')
126 execution.setVariable('UPDVfModVol_requestInfo', requestInfo)
127 execution.setVariable('UPDVfModVol_requestId', requestId)
128 //execution.setVariable('UPDVfModVol_requestId', getRequiredNodeText(execution, requestInfo, 'request-id'))
129 execution.setVariable('UPDVfModVol_source', getNodeTextForce(requestInfo, 'source'))
131 def volumeInputs = getRequiredNodeXml(execution, request, 'volume-inputs')
132 execution.setVariable('UPDVfModVol_volumeInputs', volumeInputs)
133 execution.setVariable('UPDVfModVol_volumeGroupId', getRequiredNodeText(execution, volumeInputs, 'volume-group-id'))
134 execution.setVariable('UPDVfModVol_vnfType', getRequiredNodeText(execution, volumeInputs, 'vnf-type'))
135 execution.setVariable('UPDVfModVol_vnfVersion', getRequiredNodeText(execution, volumeInputs, 'asdc-service-model-version'))
136 execution.setVariable('UPDVfModVol_serviceId', utils.getNodeText(volumeInputs, 'service-id'))
137 execution.setVariable('UPDVfModVol_aicCloudRegion', getRequiredNodeText(execution, volumeInputs, 'aic-cloud-region'))
138 execution.setVariable('UPDVfModVol_cloudRegion', getRequiredNodeText(execution, volumeInputs, 'cloud-owner'))
139 execution.setVariable('UPDVfModVol_tenantId', getRequiredNodeText(execution, volumeInputs, 'tenant-id'))
140 //execution.setVariable('UPDVfModVol_modelCustomizationId', getRequiredNodeText(execution, volumeInputs, 'model-customization-id'))
142 setBasicDBAuthHeader(execution, isDebugLogEnabled)
144 def volumeParams = utils.getNodeXml(request, 'volume-params')
145 execution.setVariable('UPDVfModVol_volumeParams', volumeParams)
149 * Prepare and send the synchronous response.
151 * @param execution The flow's execution instance.
153 public void sendSynchResponse(DelegateExecution execution, isDebugLogEnabled) {
155 def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
156 def requestId = execution.getVariable('UPDVfModVol_requestId')
157 def source = execution.getVariable('UPDVfModVol_source')
158 def progress = getNodeTextForce(requestInfo, 'progress')
159 if (progress.isEmpty()) {
162 def startTime = getNodeTextForce(requestInfo, 'start-time')
163 if (startTime.isEmpty()) {
164 startTime = System.currentTimeMillis()
166 def volumeInputs = execution.getVariable('UPDVfModVol_volumeInputs')
168 String xmlSyncResponse = """
169 <volume-request xmlns="http://org.onap/so/infra/vnf-request/v1">
171 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
172 <action>UPDATE_VF_MODULE_VOL</action>
173 <request-status>IN_PROGRESS</request-status>
174 <progress>${MsoUtils.xmlEscape(progress)}</progress>
175 <start-time>${MsoUtils.xmlEscape(startTime)}</start-time>
176 <source>${MsoUtils.xmlEscape(source)}</source>
182 def syncResponse = ''
183 def isVidRequest = execution.getVariable('UPDVfModVol_isVidRequest')
186 def volumeGroupId = execution.getVariable('volumeGroupId')
187 syncResponse = """{"requestReferences":{"instanceId":"${volumeGroupId}","requestId":"${
191 syncResponse = utils.formatXml(xmlSyncResponse)
194 logger.debug('Sync response: {}', syncResponse)
195 execution.setVariable('UPDVfModVol_syncResponseSent', true)
196 sendWorkflowResponse(execution, 200, syncResponse)
200 * Prepare a Request for querying AAI for Volume Group information using the
201 * Volume Group Id and Aic Cloud Region.
202 * @param execution The flow's execution instance.
204 public void queryAAIForVolumeGroup(DelegateExecution execution, isDebugLogEnabled) {
206 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
207 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
210 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure().cloudRegion(Defaults.CLOUD_OWNER.toString(), aicCloudRegion).volumeGroup(volumeGroupId))
211 AAIResultWrapper wrapper = getAAIClient().get(uri)
212 Optional<VolumeGroup> volumeGroup = wrapper.asBean(VolumeGroup.class)
213 if (volumeGroup.isPresent()) {
214 execution.setVariable('UPDVfModVol_aaiVolumeGroupResponse', volumeGroup.get())
215 Optional<Relationships> relationships = wrapper.getRelationships()
216 if (relationships.isPresent()) {
217 List<AAIResourceUri> tenantURIList = relationships.get().getRelatedUris(Types.TENANT)
218 if (!isEmpty(tenantURIList)) {
219 String volumeGroupTenantId = tenantURIList.get(0).getURIKeys().get(AAIFluentTypeBuilder.Types.TENANT.getUriParams().tenantId)
220 execution.setVariable('UPDVfModVol_volumeGroupTenantId', volumeGroupTenantId)
221 logger.debug("Received Tenant Id {} from AAI for Volume Group with Volume Group Id {}, AIC Cloud Region ",
222 volumeGroupTenantId, volumeGroupId, aicCloudRegion)
224 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId
225 + ", AIC Cloud Region " + aicCloudRegion)
227 execution.setVariable('UPDVfModVol_relatedVfModuleLink', relationships.get().getRelatedLinks(Types.VF_MODULE).get(0))
230 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Could not find Tenant Id element in Volume Group with Volume Group Id " + volumeGroupId
231 + ", AIC Cloud Region " + aicCloudRegion)
234 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Volume Group " + volumeGroupId + " not found at AAI")
236 }catch(BpmnError bpmnError){
239 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occured During queryAAIForGenericVnf"+e.getMessage())
244 * Query AAI service instance
246 * @param isDebugEnabled
248 public void queryAAIForGenericVnf(DelegateExecution execution, isDebugEnabled) {
250 def vnfId = execution.getVariable('vnfId')
252 AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.network().genericVnf(vnfId))
254 Optional<GenericVnf> genericVnf = getAAIClient().get(GenericVnf.class, uri)
255 if (genericVnf.isPresent()) {
256 execution.setVariable('UPDVfModVol_AAIQueryGenericVfnResponse', genericVnf.get())
258 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, 'Generic vnf ' + vnfId + ' was not found in AAI. Return code: 404.')
260 }catch(BpmnError bpmnError){
263 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occured During queryAAIForGenericVnf"+e.getMessage())
268 * Query AAI for VF Module using vf-module-id
270 * @param isDebugLogEnabled
272 public void queryAAIForVfModule(DelegateExecution execution, isDebugLogEnabled) {
274 String queryAAIVfModuleRequest = execution.getVariable('UPDVfModVol_relatedVfModuleLink')
275 execution.setVariable('UPDVfModVol_personaModelId', '')
276 AAIResourceUri uri = AAIUriFactory.createResourceFromExistingURI(Types.VF_MODULE, UriBuilder.fromPath(queryAAIVfModuleRequest).build())
278 Optional<VfModule> vfModule = getAAIClient().get(VfModule.class,uri)
279 if(vfModule.isPresent()){
280 execution.setVariable('UPDVfModVol_personaModelId',vfModule.get().getModelInvariantId())
282 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "VF Module not found at AAI")
284 }catch(BpmnError bpmnError){
287 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Error in queryAAIForVfModule: "+e.getMessage())
292 * Prepare a Request for invoking the VnfAdapterRest subflow to do
293 * a Volume Group update.
295 * @param execution The flow's execution instance.
297 public void prepVnfAdapterRest(DelegateExecution execution, isDebugLogEnabled) {
299 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
300 def cloudOwner = execution.getVariable("UPDVfModVol_cloudRegion")
301 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
302 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
304 VolumeGroup aaiVolumeGroupResponse = execution.getVariable('UPDVfModVol_aaiVolumeGroupResponse')
305 def volumeGroupHeatStackId = aaiVolumeGroupResponse.getHeatStackId()
306 def volumeGroupName = aaiVolumeGroupResponse.getVolumeGroupName()
307 def modelCustomizationId = aaiVolumeGroupResponse.getModelCustomizationId()
309 def vnfType = execution.getVariable('UPDVfModVol_vnfType')
310 def vnfVersion = execution.getVariable('UPDVfModVol_vnfVersion')
312 GenericVnf aaiGenericVnfResponse = execution.getVariable('UPDVfModVol_AAIQueryGenericVfnResponse')
313 def vnfId = aaiGenericVnfResponse.getVnfId()
314 def vnfName = aaiGenericVnfResponse.getVnfName()
317 def volumeParamsXml = execution.getVariable('UPDVfModVol_volumeParams')
318 def volumeGroupParams = transformVolumeParamsToEntries(volumeParamsXml)
320 def requestId = execution.getVariable('UPDVfModVol_requestId')
321 def serviceId = execution.getVariable('UPDVfModVol_serviceId')
323 def messageId = execution.getVariable('mso-request-id') + '-' + System.currentTimeMillis()
324 def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
325 def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host", execution)
326 if ('true'.equals(useQualifiedHostName)) {
327 notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
330 String vnfAdapterRestRequest = """
331 <updateVolumeGroupRequest>
332 <cloudSiteId>${MsoUtils.xmlEscape(aicCloudRegion)}</cloudSiteId>
333 <cloudOwner>${MsoUtils.xmlEscape(cloudOwner)}</cloudOwner>
334 <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
335 <vnfId>${MsoUtils.xmlEscape(vnfId)}</vnfId>
336 <vnfName>${MsoUtils.xmlEscape(vnfName)}</vnfName>
337 <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
338 <volumeGroupName>${MsoUtils.xmlEscape(volumeGroupName)}</volumeGroupName>
339 <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
340 <vnfType>${MsoUtils.xmlEscape(vnfType)}</vnfType>
341 <vnfVersion>${MsoUtils.xmlEscape(vnfVersion)}</vnfVersion>
342 <vfModuleType></vfModuleType>
343 <modelCustomizationUuid>${MsoUtils.xmlEscape(modelCustomizationId)}</modelCustomizationUuid>
347 <value>${MsoUtils.xmlEscape(vnfId)}</value>
351 <value>${MsoUtils.xmlEscape(vnfName)}</value>
354 <key>vf_module_id</key>
355 <value>${MsoUtils.xmlEscape(volumeGroupId)}</value>
358 <key>vf_module_name</key>
359 <value>${MsoUtils.xmlEscape(volumeGroupName)}</value>
363 <skipAAI>true</skipAAI>
365 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
366 <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
368 <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
369 <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
370 </updateVolumeGroupRequest>
372 vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
373 execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest)
374 logger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
378 * Prepare a Request for updating the DB for this Infra request.
380 * @param execution The flow's execution instance.
382 public void prepDbInfraDbRequest(DelegateExecution execution, isDebugLogEnabled) {
384 def requestId = execution.getVariable('UPDVfModVol_requestId')
386 String updateInfraRequest = """
387 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
388 xmlns:req="http://org.onap.so/requestsdb">
391 <req:updateInfraRequest>
392 <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
393 <lastModifiedBy>BPEL</lastModifiedBy>
394 <requestStatus>COMPLETE</requestStatus>
395 <progress>100</progress>
396 </req:updateInfraRequest>
401 updateInfraRequest = utils.formatXml(updateInfraRequest)
402 execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest)
403 logger.debug('Request for Update Infra Request:\n' + updateInfraRequest)
407 * Build a "CompletionHandler" request.
408 * @param execution The flow's execution instance.
410 public void prepCompletionHandlerRequest(DelegateExecution execution, requestId, action, source, isDebugLogEnabled) {
413 <aetgt:MsoCompletionRequest xmlns:aetgt="http://org.onap/so/workflow/schema/v1"
414 xmlns:ns="http://org.onap/so/request/types/v1">
415 <request-info xmlns="http://org.onap/so/infra/vnf-request/v1">
416 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
417 <action>UPDATE</action>
418 <source>${MsoUtils.xmlEscape(source)}</source>
420 <aetgt:mso-bpel-name>BPMN VF Module Volume action: UPDATE</aetgt:mso-bpel-name>
421 </aetgt:MsoCompletionRequest>
424 content = utils.formatXml(content)
425 logger.debug('Request for Completion Handler:\n' + content)
426 execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content)
430 * Build a "FalloutHandler" request.
431 * @param execution The flow's execution instance.
433 public void prepFalloutHandler(DelegateExecution execution, isDebugLogEnabled) {
434 def requestId = execution.getVariable('UPDVfModVol_requestId')
435 def source = execution.getVariable('UPDVfModVol_source')
437 String requestInfo = """
438 <request-info xmlns="http://org.onap/so/infra/vnf-request/v1">
439 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
440 <action>UPDATE</action>
441 <source>${MsoUtils.xmlEscape(source)}</source>
444 WorkflowException workflowException = execution.getVariable("WorkflowException")
445 def errorResponseCode = workflowException.getErrorCode()
446 def errorResponseMsg = workflowException.getErrorMessage()
447 def encErrorResponseMsg = ""
448 if (errorResponseMsg != null) {
449 encErrorResponseMsg = errorResponseMsg
453 <sdncadapterworkflow:FalloutHandlerRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
454 xmlns:reqtype="http://org.onap/so/request/types/v1"
455 xmlns:msoservtypes="http://org.onap/so/request/types/v1"
456 xmlns:structuredtypes="http://org.onap/so/structured/types/v1">
458 <sdncadapterworkflow:WorkflowException>
459 <sdncadapterworkflow:ErrorMessage>${MsoUtils.xmlEscape(encErrorResponseMsg)}</sdncadapterworkflow:ErrorMessage>
460 <sdncadapterworkflow:ErrorCode>${MsoUtils.xmlEscape(errorResponseCode)}</sdncadapterworkflow:ErrorCode>
461 </sdncadapterworkflow:WorkflowException>
462 </sdncadapterworkflow:FalloutHandlerRequest>
464 content = utils.formatXml(content)
465 logger.debug('Request for Fallout Handler:\n' + content)
466 execution.setVariable('UPDVfModVol_FalloutHandlerRequest', content)
470 * Create a WorkflowException for the error case where the Tenant Id from
471 * AAI did not match the Tenant Id in the incoming request.
472 * @param execution The flow's execution instance.
474 public void handleTenantIdMismatch(DelegateExecution execution, isDebugLogEnabled) {
476 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
477 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
478 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
479 def volumeGroupTenantId = execution.getVariable('UPDVfModVol_volumeGroupTenantId')
481 String errorMessage = "TenantId " + tenantId + " in incoming request does not match Tenant Id " + volumeGroupTenantId +
482 " retrieved from AAI for Volume Group Id " + volumeGroupId + ", AIC Cloud Region " + aicCloudRegion
484 ExceptionUtil exceptionUtil = new ExceptionUtil()
485 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), 'Error in ' +
486 'UpdateVfModuleVol: ' + errorMessage, "BPMN", ErrorCode.UnknownError.getValue(), "Exception")
487 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)
491 * Create a WorkflowException for the error case where the Personal Model Id from
492 * AAI did not match the model invariant ID in the incoming request.
493 * @param execution The flow's execution instance.
495 public void handlePersonaModelIdMismatch(DelegateExecution execution, isDebugLogEnabled) {
497 def modelInvariantId = execution.getVariable('UPDVfModVol_modelInvariantId')
498 def personaModelId = execution.getVariable('UPDVfModVol_personaModelId')
500 String errorMessage = "Model Invariant ID " + modelInvariantId + " in incoming request does not match persona model ID " + personaModelId +
501 " retrieved from AAI for Volume Group Id "
503 ExceptionUtil exceptionUtil = new ExceptionUtil()
504 logger.error(LoggingAnchor.FIVE, MessageEnum.BPMN_GENERAL_EXCEPTION_ARG.toString(), 'Error in ' +
505 'UpdateVfModuleVol: ' + errorMessage, "BPMN", ErrorCode.UnknownError.getValue(), "Exception")
506 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMessage)