Springboot 2.0 upgrade
[so.git] / bpmn / so-bpmn-infrastructure-common / src / main / groovy / org / onap / so / bpmn / infrastructure / scripts / UpdateVfModuleVolume.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.onap.so.bpmn.infrastructure.scripts
22
23 import org.apache.commons.collections.CollectionUtils
24 import org.camunda.bpm.engine.delegate.BpmnError
25 import org.camunda.bpm.engine.delegate.DelegateExecution
26 import org.onap.aai.domain.yang.VolumeGroup
27 import org.onap.so.bpmn.common.scripts.ExceptionUtil
28 import org.onap.so.bpmn.common.scripts.MsoUtils
29 import org.onap.so.bpmn.common.scripts.VfModuleBase
30 import org.onap.so.bpmn.core.UrnPropertiesReader
31 import org.onap.so.bpmn.core.WorkflowException
32 import org.onap.so.client.aai.AAIObjectType
33 import org.onap.so.client.aai.entities.AAIResultWrapper
34 import org.onap.so.client.aai.entities.Relationships
35 import org.onap.so.client.aai.entities.uri.AAIResourceUri
36 import org.onap.so.client.aai.entities.uri.AAIUriFactory
37 import org.onap.so.constants.Defaults
38 import org.onap.so.logger.MessageEnum
39 import org.onap.so.logger.MsoLogger
40 import static  org.apache.commons.lang.StringUtils.isEmpty
41
42 class UpdateVfModuleVolume extends VfModuleBase {
43         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, UpdateVfModuleVolume.class)
44         
45         ExceptionUtil exceptionUtil = new ExceptionUtil()
46
47         /**
48          * Initialize the flow's variables.
49          *
50          * @param execution The flow's execution instance.
51          */
52         private void initProcessVariables(DelegateExecution execution) {
53                 execution.setVariable('prefix', 'UPDVfModVol_')
54                 execution.setVariable('UPDVfModVol_Request', null)
55                 execution.setVariable('UPDVfModVol_requestInfo', null)
56                 execution.setVariable('UPDVfModVol_requestId', null)
57                 execution.setVariable('UPDVfModVol_source', null)
58                 execution.setVariable('UPDVfModVol_volumeInputs', null)
59                 execution.setVariable('UPDVfModVol_volumeGroupId', null)
60                 execution.setVariable('UPDVfModVol_vnfType', null)
61                 execution.setVariable('UPDVfModVol_serviceId', null)
62                 execution.setVariable('UPDVfModVol_aicCloudRegion', null)
63                 execution.setVariable('UPDVfModVol_tenantId', null)
64                 execution.setVariable('UPDVfModVol_volumeParams', null)
65                 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', null)
66                 execution.setVariable('UPDVfModVol_volumeGroupTenantId', null)
67                 execution.setVariable('UpdateVfModuleVolumeSuccessIndicator', false)
68         }
69
70         /**
71          * Check for missing elements in the received request.
72          *
73          * @param execution The flow's execution instance.
74          */
75         @Override
76         public void preProcessRequest(DelegateExecution execution) {
77                 def method = getClass().getSimpleName() + '.preProcessRequest(' +
78                         'execution=' + execution.getId() +
79                         ')'
80
81                 msoLogger.trace('Entered ' + method)
82
83                 try {
84                         initProcessVariables(execution)
85                         String request = validateRequest(execution)
86
87                         def requestInfo = getRequiredNodeXml(execution, request, 'request-info')
88                         execution.setVariable('UPDVfModVol_requestInfo', requestInfo)
89                         execution.setVariable('UPDVfModVol_requestId', getRequiredNodeText(execution, requestInfo, 'request-id'))
90                         execution.setVariable('UPDVfModVol_source', getNodeTextForce(requestInfo, 'source'))
91
92                         def volumeInputs = getRequiredNodeXml(execution, request, 'volume-inputs')
93                         execution.setVariable('UPDVfModVol_volumeInputs', volumeInputs)
94                         execution.setVariable('UPDVfModVol_volumeGroupId', getRequiredNodeText(execution, volumeInputs, 'volume-group-id'))
95                         execution.setVariable('UPDVfModVol_vnfType', getRequiredNodeText(execution, volumeInputs, 'vnf-type'))
96                         execution.setVariable('UPDVfModVol_serviceId', getRequiredNodeText(execution, volumeInputs, 'service-id'))
97                         execution.setVariable('UPDVfModVol_aicCloudRegion', getRequiredNodeText(execution, volumeInputs, 'aic-cloud-region'))
98                         execution.setVariable('UPDVfModVol_tenantId', getRequiredNodeText(execution, volumeInputs, 'tenant-id'))
99
100                         def volumeParams = utils.getNodeXml(request, 'volume-params')
101                         execution.setVariable('UPDVfModVol_volumeParams', volumeParams)
102
103                         msoLogger.trace('Exited ' + method)
104                         msoLogger.debug("UpdateVfModuleVolume request: " + request)
105                 } catch (BpmnError bpmnError) {
106                         throw bpmnError
107                 } catch (Exception e) {
108                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
109                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in preProcessRequest(): ' + e.getMessage())
110                 }
111         }
112
113         /**
114          * Prepare and send the synchronous response.
115          *
116          * @param execution The flow's execution instance.
117          */
118         public void sendSynchResponse(DelegateExecution execution) {
119                 def method = getClass().getSimpleName() + '.sendSynchResponse(' +
120                         'execution=' + execution.getId() +
121                         ')'
122
123                 msoLogger.trace('Entered ' + method)
124
125                 try {
126                         def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
127                         def requestId = execution.getVariable('UPDVfModVol_requestId')
128                         def source = execution.getVariable('UPDVfModVol_source')
129                         def progress = getNodeTextForce(requestInfo, 'progress')
130                         if (progress.isEmpty()) {
131                                 progress = '0'
132                         }
133                         def startTime = getNodeTextForce(requestInfo, 'start-time')
134                         if (startTime.isEmpty()) {
135                                 startTime = System.currentTimeMillis()
136                         }
137                         def volumeInputs = execution.getVariable('UPDVfModVol_volumeInputs')
138
139                         String synchResponse = """
140                                 <volume-request xmlns="http://org.onap/so/infra/vnf-request/v1">
141                                         <request-info>
142                                                 <request-id>${MsoUtils.xmlEscape(requestId)}</request-id>
143                                                 <action>UPDATE_VF_MODULE_VOL</action>
144                                                 <request-status>IN_PROGRESS</request-status>
145                                                 <progress>${MsoUtils.xmlEscape(progress)}</progress>
146                                                 <start-time>${MsoUtils.xmlEscape(startTime)}</start-time>
147                                                 <source>${MsoUtils.xmlEscape(source)}</source>
148                                         </request-info>
149                                         ${volumeInputs}
150                                 </volume-request>
151                         """
152
153                         synchResponse = utils.formatXml(synchResponse)
154                         sendWorkflowResponse(execution, 200, synchResponse)
155                         msoLogger.debug("UpdateVfModuleVolume Synch Response: " + synchResponse)
156                 } catch (BpmnError e) {
157                         throw e
158                 } catch (Exception e) {
159                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
160                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in sendSynchResponse(): ' + e.getMessage())
161                 }
162         }
163
164         /**
165          * Prepare a Request for querying AAI for Volume Group information using the
166          * Volume Group Id and Aic Cloud Region.
167          *
168          * @param execution The flow's execution instance.
169          */
170         public void queryAAIForVolumeGroup(DelegateExecution execution) {
171                 def method = getClass().getSimpleName() + '.queryAAIForVolumeGroup(' +
172                         'execution=' + execution.getId() +
173                         ')'
174
175                 msoLogger.trace('Entered ' + method)
176
177                 try {
178                         def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
179                         def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
180                         AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.VOLUME_GROUP, Defaults.CLOUD_OWNER.toString(),aicCloudRegion,volumeGroupId)
181                         AAIResultWrapper wrapper =  getAAIClient().get(uri)
182                         Optional<VolumeGroup> volumeGroup = wrapper.asBean(VolumeGroup.class)
183                         if(volumeGroup.isPresent()){
184                                 def heatStackId = volumeGroup.get().getHeatStackId()
185                                 execution.setVariable('UPDVfModVol_volumeGroupHeatStackId', heatStackId)
186                                 Optional<Relationships> relationships = wrapper.getRelationships()
187                                 if(relationships.isPresent()){
188                                         List<AAIResourceUri> resourceUriList = relationships.get().getRelatedAAIUris(AAIObjectType.TENANT)
189                                         if(CollectionUtils.isNotEmpty(resourceUriList)){
190                                                 AAIResourceUri tenantUri = resourceUriList.get(0)
191                                                 String volumeGroupTenantId = tenantUri.getURIKeys().get("tenant-id")
192                                                 if( isEmpty(volumeGroupTenantId)){
193                                                         exceptionUtil.buildAndThrowWorkflowException(execution,2500,"Could not find Tenant Id element in Volume Group with Volume Group Id" + volumeGroupId + ", AIC Cloud Region" + aicCloudRegion)
194                                                 }
195                                                 execution.setVariable('UPDVfModVol_volumeGroupTenantId', volumeGroupTenantId)
196                                                 msoLogger.debug("Received Tenant Id: " + volumeGroupTenantId + "from AAI for Volume Group with Volume Group Id: " + volumeGroupId + ", AIC Cloud Region" + aicCloudRegion)
197                                         }else{
198                                                 exceptionUtil.buildAndThrowWorkflowException(execution,2500,"Could not find Tenant Id element in Volume Group with Volume Group Id" + volumeGroupId + ", AIC Cloud Region" + aicCloudRegion)
199                                         }
200                                 }
201                         }else{
202                                 exceptionUtil.buildAndThrowWorkflowException(execution,2500,"Volume Group" + volumeGroupId + " not found at AAI")
203                         }
204                         msoLogger.trace('Exited ' + method)
205                 } catch (BpmnError e) {
206                         throw e
207                 } catch (Exception e) {
208                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
209                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in queryAAIForVolumeGroup(): ' + e.getMessage())
210                 }
211         }
212
213         /**
214          * Prepare a Request for invoking the VnfAdapterRest subflow to do
215          * a Volume Group update.
216          *
217          * @param execution The flow's execution instance.
218          */
219         public void prepVnfAdapterRest(DelegateExecution execution) {
220                 def method = getClass().getSimpleName() + '.prepVnfAdapterRest(' +
221                         'execution=' + execution.getId() +
222                         ')'
223
224                 msoLogger.trace('Entered ' + method)
225
226                 try {
227                         def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
228                         def tenantId = execution.getVariable('UPDVfModVol_tenantId')
229                         def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
230                         def volumeGroupHeatStackId = execution.getVariable('UPDVfModVol_volumeGroupHeatStackId')
231                         def vnfType = execution.getVariable('UPDVfModVol_vnfType')
232
233                         def volumeParamsXml = execution.getVariable('UPDVfModVol_volumeParams')
234                         def volumeGroupParams = transformParamsToEntries(volumeParamsXml)
235
236                         def requestId = execution.getVariable('UPDVfModVol_requestId')
237                         def serviceId = execution.getVariable('UPDVfModVol_serviceId')
238
239                         def messageId = execution.getVariable('mso-request-id') + '-' + System.currentTimeMillis()
240                         def notificationUrl = createCallbackURL(execution, "VNFAResponse", messageId)
241                         def useQualifiedHostName = UrnPropertiesReader.getVariable("mso.use.qualified.host",execution)
242                         if ('true'.equals(useQualifiedHostName)) {
243                                         notificationUrl = utils.getQualifiedHostNameForCallback(notificationUrl)
244                         }
245
246                         String vnfAdapterRestRequest = """
247                                 <updateVolumeGroupRequest>
248                                         <cloudSiteId>${MsoUtils.xmlEscape(aicCloudRegion)}</cloudSiteId>
249                                         <tenantId>${MsoUtils.xmlEscape(tenantId)}</tenantId>
250                                         <volumeGroupId>${MsoUtils.xmlEscape(volumeGroupId)}</volumeGroupId>
251                                         <volumeGroupStackId>${MsoUtils.xmlEscape(volumeGroupHeatStackId)}</volumeGroupStackId>
252                                         <vnfType>${MsoUtils.xmlEscape(vnfType)}</vnfType>
253                                         <vnfVersion></vnfVersion>
254                                         <vfModuleType></vfModuleType>
255                                         <volumeGroupParams>
256                                                 ${volumeGroupParams}
257                                     </volumeGroupParams>
258                                         <skipAAI>true</skipAAI>
259                                     <msoRequest>
260                                         <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
261                                         <serviceInstanceId>${MsoUtils.xmlEscape(serviceId)}</serviceInstanceId>
262                                     </msoRequest>
263                                     <messageId>${MsoUtils.xmlEscape(messageId)}</messageId>
264                                     <notificationUrl>${MsoUtils.xmlEscape(notificationUrl)}</notificationUrl>
265                                 </updateVolumeGroupRequest>
266                         """
267                         vnfAdapterRestRequest = utils.formatXml(vnfAdapterRestRequest)
268                         execution.setVariable('UPDVfModVol_vnfAdapterRestRequest', vnfAdapterRestRequest)
269                         msoLogger.debug('Request for VNFAdapter Rest:\n' + vnfAdapterRestRequest)
270
271                         msoLogger.debug("UpdateVfModuleVolume Request for VNFAdapter Rest: " + vnfAdapterRestRequest)
272                         msoLogger.trace('Exited ' + method)
273                 } catch (BpmnError e) {
274                         throw e
275                 } catch (Exception e) {
276                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
277                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in prepVnfAdapterRest(): ' + e.getMessage())
278                 }
279         }
280
281         /**
282          * Prepare a Request for updating the DB for this Infra request.
283          *
284          * @param execution The flow's execution instance.
285          */
286         public void prepDbInfraDbRequest(DelegateExecution execution) {
287                 def method = getClass().getSimpleName() + '.prepDbInfraDbRequest(' +
288                         'execution=' + execution.getId() +
289                         ')'
290
291                 msoLogger.trace('Entered ' + method)
292
293                 try {
294                         def requestId = execution.getVariable('UPDVfMod_requestId')
295
296                         String updateInfraRequest = """
297                                 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
298                                                 xmlns:req="http://org.onap.so/requestsdb">
299                                         <soapenv:Header/>
300                                         <soapenv:Body>
301                                                 <req:updateInfraRequest>
302                                                         <requestId>${MsoUtils.xmlEscape(requestId)}</requestId>
303                                                         <lastModifiedBy>BPEL</lastModifiedBy>
304                                                         <requestStatus>COMPLETE</requestStatus>
305                                                         <progress>100</progress>
306                                                 </req:updateInfraRequest>
307                                         </soapenv:Body>
308                                 </soapenv:Envelope>
309                         """
310
311                         updateInfraRequest = utils.formatXml(updateInfraRequest)
312                         execution.setVariable('UPDVfModVol_updateInfraRequest', updateInfraRequest)
313                         msoLogger.debug('Request for Update Infra Request:\n' + updateInfraRequest)
314
315                         msoLogger.debug("UpdateVfModuleVolume Request for Updating DB for Infra: " + updateInfraRequest)
316                         msoLogger.trace('Exited ' + method)
317                 } catch (BpmnError e) {
318                         throw e
319                 } catch (Exception e) {
320                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
321                         exceptionUtil.buildWorkflowException(execution, 1002, 'Error in prepDbInfraDbRequest(): ' + e.getMessage())
322                 }
323         }
324
325         /**
326          * Build a "CompletionHandler" request.
327          *
328          * @param execution The flow's execution instance.
329          */
330         public void prepCompletionHandlerRequest(DelegateExecution execution) {
331                 def method = getClass().getSimpleName() + '.prepCompletionHandlerRequest(' +
332                         'execution=' + execution.getId() +
333                         ')'
334
335                 msoLogger.trace('Entered ' + method)
336
337                 try {
338                         def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
339
340                         String content = """
341                                 <sdncadapterworkflow:MsoCompletionRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
342                                                 xmlns:reqtype="http://org.onap/so/request/types/v1">
343                                         ${requestInfo}
344                                         <sdncadapterworkflow:mso-bpel-name>MSO_ACTIVATE_BPEL</sdncadapterworkflow:mso-bpel-name>
345                                 </sdncadapterworkflow:MsoCompletionRequest>
346                         """
347
348                         content = utils.formatXml(content)
349                         msoLogger.debug('Request for Completion Handler:\n' + content)
350                         msoLogger.debug("UpdateVfModuleVolume Completion Handler request: " + content)
351                         execution.setVariable('UPDVfModVol_CompletionHandlerRequest', content)
352
353                         msoLogger.trace('Exited ' + method)
354                 } catch (BpmnError e) {
355                         throw e
356                 } catch (Exception e) {
357                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
358                         exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in prepCompletionHandlerRequest(): ' + e.getMessage())
359                 }
360         }
361
362         /**
363          * Build a "FalloutHandler" request.
364          *
365          * @param execution The flow's execution instance.
366          */
367         public void prepFalloutHandler(DelegateExecution execution) {
368                 def method = getClass().getSimpleName() + '.prepFalloutHandler(' +
369                         'execution=' + execution.getId() +
370                         ')'
371
372                 msoLogger.trace('Entered ' + method)
373
374                 try {
375                         def requestInfo = execution.getVariable('UPDVfModVol_requestInfo')
376
377                         def WorkflowException workflowException = execution.getVariable("WorkflowException")
378                         def errorResponseCode = workflowException.getErrorCode()
379                         def errorResponseMsg = workflowException.getErrorMessage()
380                         def encErrorResponseMsg = ""
381                         if (errorResponseMsg != null) {
382                                 encErrorResponseMsg = errorResponseMsg
383                         }
384
385                         String content = """
386                                 <sdncadapterworkflow:FalloutHandlerRequest xmlns:sdncadapterworkflow="http://org.onap/so/workflow/schema/v1"
387                                                 xmlns:reqtype="http://org.onap/so/request/types/v1"
388                                                 xmlns:msoservtypes="http://org.onap/so/request/types/v1"
389                                                 xmlns:structuredtypes="http://org.onap/so/structured/types/v1">
390                                         ${requestInfo}
391                                         <sdncadapterworkflow:WorkflowException>
392                                                 <sdncadapterworkflow:ErrorMessage>${MsoUtils.xmlEscape(encErrorResponseMsg)}</sdncadapterworkflow:ErrorMessage>
393                                                 <sdncadapterworkflow:ErrorCode>${MsoUtils.xmlEscape(errorResponseCode)}</sdncadapterworkflow:ErrorCode>
394                                         </sdncadapterworkflow:WorkflowException>
395                                 </sdncadapterworkflow:FalloutHandlerRequest>
396                         """
397                         content = utils.formatXml(content)
398                         msoLogger.debug('Request for Fallout Handler:\n' + content)
399                         msoLogger.debug("UpdateVfModuleVolume Fallout request: " + content)
400                         execution.setVariable('UPDVfModVol_FalloutHandlerRequest', content)
401
402                         msoLogger.trace('Exited ' + method)
403                 } catch (BpmnError e) {
404                         throw e
405                 } catch (Exception e) {
406                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Caught exception in ' + method, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception is:\n" + e)
407                         exceptionUtil.buildWorkflowException(execution, 1002, 'Error in prepFalloutHandler(): ' + e.getMessage())
408                 }
409         }
410
411         /**
412          * Create a WorkflowException for the error case where the Tenant Id from
413          * AAI did not match the Tenant Id in the incoming request.
414          *
415          * @param execution The flow's execution instance.
416          */
417         public void handleTenantIdMismatch(DelegateExecution execution) {
418                 def method = getClass().getSimpleName() + '.handleTenantIdMismatch(' +
419                         'execution=' + execution.getId() +
420                         ')'
421
422                 msoLogger.trace('Entered ' + method)
423
424                 String processKey = getProcessKey(execution)
425                 def volumeGroupId = execution.getVariable('UPDVfModVol_volumeGroupId')
426                 def aicCloudRegion = execution.getVariable('UPDVfModVol_aicCloudRegion')
427                 def tenantId = execution.getVariable('UPDVfModVol_tenantId')
428                 def volumeGroupTenantId = execution.getVariable('UPDVfModVol_volumeGroupTenantId')
429
430                 def String errorMessage = 'TenantId \'' + tenantId + '\' in incoming request does not match Tenant Id \'' + volumeGroupTenantId +
431                         '\' retrieved from AAI for Volume Group Id \'' + volumeGroupId + '\', AIC Cloud Region \'' + aicCloudRegion + '\''
432
433                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, 'Error in UpdateVfModuleVol: ' + errorMessage, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "Exception")
434
435                 WorkflowException exception = new WorkflowException(processKey, 5000, errorMessage)
436                 execution.setVariable("WorkflowException", exception)
437
438                 msoLogger.trace('Exited ' + method)
439                 msoLogger.debug("UpdateVfModuleVolume workflowException in Tenant Mismatch: " + errorMessage)
440         }
441 }