Correct the SO 1.3.7 as patch release
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / OofUtils.groovy
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2018 Intel Corp. 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.common.scripts
22
23 import org.camunda.bpm.engine.delegate.DelegateExecution
24 import org.onap.so.bpmn.common.scripts.AbstractServiceTaskProcessor
25 import org.onap.so.bpmn.common.scripts.ExceptionUtil
26 import org.onap.so.bpmn.core.UrnPropertiesReader
27 import org.onap.so.bpmn.core.domain.HomingSolution
28 import org.onap.so.bpmn.core.domain.ModelInfo
29 import org.onap.so.bpmn.core.domain.Resource
30 import org.onap.so.bpmn.core.domain.AllottedResource
31 import org.onap.so.bpmn.core.domain.ServiceDecomposition
32 import org.onap.so.bpmn.core.domain.ServiceInstance
33 import org.onap.so.bpmn.core.domain.Subscriber
34 import org.onap.so.bpmn.core.domain.VnfResource
35 import org.onap.so.bpmn.core.json.JsonUtils
36 import org.onap.so.db.catalog.beans.CloudSite
37 import org.onap.so.db.catalog.beans.HomingInstance
38 import javax.ws.rs.core.UriBuilder
39 import org.onap.so.bpmn.common.util.OofInfraUtils
40 import static org.onap.so.bpmn.common.scripts.GenericUtils.*
41
42 class OofUtils {
43     ExceptionUtil exceptionUtil = new ExceptionUtil()
44     JsonUtils jsonUtil = new JsonUtils()
45     OofInfraUtils oofInfraUtils = new OofInfraUtils()
46
47     private AbstractServiceTaskProcessor utils
48
49     OofUtils(AbstractServiceTaskProcessor taskProcessor) {
50         this.utils = taskProcessor
51     }
52
53     /**
54      * This method builds the service-agnostic
55      * OOF json request to get a homing solution
56      * and license solution
57      *
58      * @param execution
59      * @param requestId
60      * @param decomposition - ServiceDecomposition object
61      * @param customerLocation -
62      * @param existingCandidates -
63      * @param excludedCandidates -
64      * @param requiredCandidates -
65      *
66      * @return request - OOF v1 payload - https://wiki.onap.org/pages/viewpage.action?pageId=25435066
67      */
68     String buildRequest(DelegateExecution execution,
69                         String requestId,
70                         ServiceDecomposition decomposition,
71                         Subscriber subscriber = null,
72                         Map customerLocation,
73                         ArrayList existingCandidates = null,
74                         ArrayList excludedCandidates = null,
75                         ArrayList requiredCandidates = null) {
76         def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
77         utils.log("DEBUG", "Started Building OOF Request", isDebugEnabled)
78         String callbackEndpoint = UrnPropertiesReader.getVariable("mso.oof.callbackEndpoint", execution)
79         utils.log("DEBUG", "mso.oof.callbackEndpoint is: " + callbackEndpoint, isDebugEnabled)
80         try {
81             def callbackUrl = utils.createHomingCallbackURL(callbackEndpoint, "oofResponse", requestId)
82             utils.log("DEBUG", "callbackUrl is: " + callbackUrl, isDebugEnabled)
83
84
85             def transactionId = requestId
86             utils.log("DEBUG", "transactionId is: " + transactionId, isDebugEnabled)
87             //ServiceInstance Info
88             ServiceInstance serviceInstance = decomposition.getServiceInstance()
89             def serviceInstanceId = ""
90             def serviceName = ""
91
92             serviceInstanceId = execution.getVariable("serviceInstanceId")
93             utils.log("DEBUG", "serviceInstanceId is: " + serviceInstanceId, isDebugEnabled)
94             serviceName = execution.getVariable("subscriptionServiceType")
95             utils.log("DEBUG", "serviceName is: " + serviceName, isDebugEnabled)
96
97             if (serviceInstanceId == null || serviceInstanceId == "null") {
98                 utils.log("DEBUG", "Unable to obtain Service Instance Id", isDebugEnabled)
99                 exceptionUtil.buildAndThrowWorkflowException(execution, 400, "Internal Error - Unable to " +
100                         "obtain Service Instance Id, execution.getVariable(\"serviceInstanceId\") is null")
101             }
102             if (serviceName == null || serviceName == "null") {
103                 utils.log("DEBUG", "Unable to obtain Service Name", isDebugEnabled)
104                 exceptionUtil.buildAndThrowWorkflowException(execution, 400, "Internal Error - Unable to " +
105                         "obtain Service Name, execution.getVariable(\"subscriptionServiceType\") is null")
106             }
107             //Model Info
108             ModelInfo model = decomposition.getModelInfo()
109             utils.log("DEBUG", "ModelInfo: " + model.toString(), isDebugEnabled)
110             String modelType = model.getModelType()
111             String modelInvariantId = model.getModelInvariantUuid()
112             String modelVersionId = model.getModelUuid()
113             String modelName = model.getModelName()
114             String modelVersion = model.getModelVersion()
115             //Subscriber Info
116             String subscriberId = ""
117             String subscriberName = ""
118             String commonSiteId = ""
119             if (subscriber != null) {
120                 subscriberId = subscriber.getGlobalId()
121                 subscriberName = subscriber.getName()
122                 commonSiteId = subscriber.getCommonSiteId()
123             }
124
125             //Determine RequestType
126             //TODO Figure out better way to determine this
127             String requestType = "create"
128             List<Resource> resources = decomposition.getServiceResources()
129             for (Resource r : resources) {
130                 HomingSolution currentSolution = (HomingSolution) r.getCurrentHomingSolution()
131                 if (currentSolution != null) {
132                     requestType = "speed changed"
133                 }
134             }
135
136             //Demands
137             String placementDemands = ""
138             StringBuilder sb = new StringBuilder()
139             List<AllottedResource> allottedResourceList = decomposition.getAllottedResources()
140             List<VnfResource> vnfResourceList = decomposition.getVnfResources()
141
142             if (allottedResourceList == null || allottedResourceList.isEmpty()) {
143                 utils.log("DEBUG", "Allotted Resources List is empty - will try to get service VNFs instead.",
144                         isDebugEnabled)
145             } else {
146                 for (AllottedResource resource : allottedResourceList) {
147                     utils.log("DEBUG", "Allotted Resource: " + resource.toString(),
148                             isDebugEnabled)
149                     def serviceResourceId = resource.getResourceId()
150                     def toscaNodeType = resource.getToscaNodeType()
151                     def resourceModuleName = toscaNodeType.substring(toscaNodeType.lastIndexOf(".") + 1)
152                     def resourceModelInvariantId = resource.getModelInfo().getModelInvariantUuid()
153                     def resourceModelVersionId = resource.getModelInfo().getModelUuid()
154                     def resourceModelName = resource.getModelInfo().getModelName()
155                     def resourceModelVersion = resource.getModelInfo().getModelVersion()
156                     def resourceModelType = resource.getModelInfo().getModelType()
157                     def tenantId = execution.getVariable("tenantId")
158                     def requiredCandidatesJson = ""
159
160                     requiredCandidatesJson = createCandidateJson(
161                             existingCandidates,
162                             excludedCandidates,
163                             requiredCandidates)
164
165                     String demand =
166                             "      {\n" +
167                                     "      \"resourceModuleName\": \"${resourceModuleName}\",\n" +
168                                     "      \"serviceResourceId\": \"${serviceResourceId}\",\n" +
169                                     "      \"tenantId\": \"${tenantId}\",\n" +
170                                     "      \"resourceModelInfo\": {\n" +
171                                     "        \"modelInvariantId\": \"${resourceModelInvariantId}\",\n" +
172                                     "        \"modelVersionId\": \"${resourceModelVersionId}\",\n" +
173                                     "        \"modelName\": \"${resourceModelName}\",\n" +
174                                     "        \"modelType\": \"${resourceModelType}\",\n" +
175                                     "        \"modelVersion\": \"${resourceModelVersion}\",\n" +
176                                     "        \"modelCustomizationName\": \"\"\n" +
177                                     "        }" + requiredCandidatesJson + "\n" +
178                                     "      },"
179
180                     placementDemands = sb.append(demand)
181                 }
182             }
183
184             if (vnfResourceList == null || vnfResourceList.isEmpty()) {
185                 utils.log("DEBUG", "VNF Resources List is empty",
186                         isDebugEnabled)
187             } else {
188
189                 for (VnfResource vnfResource : vnfResourceList) {
190                     utils.log("DEBUG", "VNF Resource: " + vnfResource.toString(),
191                             isDebugEnabled)
192                     ModelInfo vnfResourceModelInfo = vnfResource.getModelInfo()
193                     def toscaNodeType = vnfResource.getToscaNodeType()
194                     def resourceModuleName = toscaNodeType.substring(toscaNodeType.lastIndexOf(".") + 1)
195                     def serviceResourceId = vnfResource.getResourceId()
196                     def resourceModelInvariantId = vnfResourceModelInfo.getModelInvariantUuid()
197                     def resourceModelName = vnfResourceModelInfo.getModelName()
198                     def resourceModelVersion = vnfResourceModelInfo.getModelVersion()
199                     def resourceModelVersionId = vnfResourceModelInfo.getModelUuid()
200                     def resourceModelType = vnfResourceModelInfo.getModelType()
201                     def tenantId = execution.getVariable("tenantId")
202                     def requiredCandidatesJson = ""
203
204
205                     String placementDemand =
206                             "      {\n" +
207                                     "      \"resourceModuleName\": \"${resourceModuleName}\",\n" +
208                                     "      \"serviceResourceId\": \"${serviceResourceId}\",\n" +
209                                     "      \"tenantId\": \"${tenantId}\",\n" +
210                                     "      \"resourceModelInfo\": {\n" +
211                                     "        \"modelInvariantId\": \"${resourceModelInvariantId}\",\n" +
212                                     "        \"modelVersionId\": \"${resourceModelVersionId}\",\n" +
213                                     "        \"modelName\": \"${resourceModelName}\",\n" +
214                                     "        \"modelType\": \"${resourceModelType}\",\n" +
215                                     "        \"modelVersion\": \"${resourceModelVersion}\",\n" +
216                                     "        \"modelCustomizationName\": \"\"\n" +
217                                     "        }" + requiredCandidatesJson + "\n" +
218                                     "      },"
219
220                     placementDemands = sb.append(placementDemand)
221                 }
222                 placementDemands = placementDemands.substring(0, placementDemands.length() - 1)
223             }
224
225             /* Commenting Out Licensing as OOF doesn't support for Beijing
226         String licenseDemands = ""
227         sb = new StringBuilder()
228         if (vnfResourceList.isEmpty() || vnfResourceList == null) {
229             utils.log("DEBUG", "Vnf Resources List is Empty", isDebugEnabled)
230         } else {
231             for (VnfResource vnfResource : vnfResourceList) {
232                 ModelInfo vnfResourceModelInfo = vnfResource.getModelInfo()
233                 def resourceInstanceType = vnfResource.getResourceType()
234                 def serviceResourceId = vnfResource.getResourceId()
235                 def resourceModuleName = vnfResource.getResourceType()
236                 def resouceModelInvariantId = vnfResourceModelInfo.getModelInvariantUuid()
237                 def resouceModelName = vnfResourceModelInfo.getModelName()
238                 def resouceModelVersion = vnfResourceModelInfo.getModelVersion()
239                 def resouceModelVersionId = vnfResourceModelInfo.getModelUuid()
240                 def resouceModelType = vnfResourceModelInfo.getModelType()
241
242                 // TODO Add Existing Licenses to demand
243                 //"existingLicenses": {
244                 //"entitlementPoolUUID": ["87257b49-9602-4ca1-9817-094e52bc873b",
245                 // "43257b49-9602-4fe5-9337-094e52bc9435"],
246                 //"licenseKeyGroupUUID": ["87257b49-9602-4ca1-9817-094e52bc873b",
247                 // "43257b49-9602-4fe5-9337-094e52bc9435"]
248                 //}
249
250                     String licenseDemand =
251                         "{\n" +
252                         "\"resourceModuleName\": \"${resourceModuleName}\",\n" +
253                         "\"serviceResourceId\": \"${serviceResourceId}\",\n" +
254                         "\"resourceInstanceType\": \"${resourceInstanceType}\",\n" +
255                         "\"resourceModelInfo\": {\n" +
256                         "  \"modelInvariantId\": \"${resouceModelInvariantId}\",\n" +
257                         "  \"modelVersionId\": \"${resouceModelVersionId}\",\n" +
258                         "  \"modelName\": \"${resouceModelName}\",\n" +
259                         "  \"modelType\": \"${resouceModelType}\",\n" +
260                         "  \"modelVersion\": \"${resouceModelVersion}\",\n" +
261                         "  \"modelCustomizationName\": \"\"\n" +
262                         "  }\n"
263                         "},"
264
265                 licenseDemands = sb.append(licenseDemand)
266             }
267             licenseDemands = licenseDemands.substring(0, licenseDemands.length() - 1)
268         }*/
269
270             String request =
271                     "{\n" +
272                             "  \"requestInfo\": {\n" +
273                             "    \"transactionId\": \"${transactionId}\",\n" +
274                             "    \"requestId\": \"${requestId}\",\n" +
275                             "    \"callbackUrl\": \"${callbackUrl}\",\n" +
276                             "    \"sourceId\": \"so\",\n" +
277                             "    \"requestType\": \"${requestType}\"," +
278                             "    \"numSolutions\": 1,\n" +
279                             "    \"optimizers\": [\"placement\"],\n" +
280                             "    \"timeout\": 600\n" +
281                             "    },\n" +
282                             "  \"placementInfo\": {\n" +
283                             "    \"requestParameters\": {\n" +
284                             "      \"customerLatitude\": \"${customerLocation.customerLatitude}\",\n" +
285                             "      \"customerLongitude\": \"${customerLocation.customerLongitude}\",\n" +
286                             "      \"customerName\": \"${customerLocation.customerName}\"\n" +
287                             "    }," +
288                             "    \"subscriberInfo\": { \n" +
289                             "      \"globalSubscriberId\": \"${subscriberId}\",\n" +
290                             "      \"subscriberName\": \"${subscriberName}\",\n" +
291                             "      \"subscriberCommonSiteId\": \"${commonSiteId}\"\n" +
292                             "    },\n" +
293                             "    \"placementDemands\": [\n" +
294                             "      ${placementDemands}\n" +
295                             "      ]\n" +
296                             "    },\n" +
297                             "  \"serviceInfo\": {\n" +
298                             "    \"serviceInstanceId\": \"${serviceInstanceId}\",\n" +
299                             "    \"serviceName\": \"${serviceName}\",\n" +
300                             "    \"modelInfo\": {\n" +
301                             "      \"modelType\": \"${modelType}\",\n" +
302                             "      \"modelInvariantId\": \"${modelInvariantId}\",\n" +
303                             "      \"modelVersionId\": \"${modelVersionId}\",\n" +
304                             "      \"modelName\": \"${modelName}\",\n" +
305                             "      \"modelVersion\": \"${modelVersion}\",\n" +
306                             "      \"modelCustomizationName\": \"\"\n" +
307                             "    }\n" +
308                             "  }\n" +
309                             "}"
310
311
312             utils.log("DEBUG", "Completed Building OOF Request", isDebugEnabled)
313             return request
314         } catch (Exception ex) {
315              utils.log("DEBUG", "buildRequest Exception: " + ex, isDebugEnabled)
316         }
317     }
318
319     /**
320      * This method validates the callback response
321      * from OOF. If the response contains an
322      * exception the method will build and throw
323      * a workflow exception.
324      *
325      * @param execution
326      * @param response - the async callback response from oof
327      */
328     Void validateCallbackResponse(DelegateExecution execution, String response) {
329         def isDebugEnabled = execution.getVariable("isDebugLogEnabled")
330         String placements = ""
331         if (isBlank(response)) {
332             exceptionUtil.buildAndThrowWorkflowException(execution, 5000, "OOF Async Callback Response is Empty")
333         } else {
334             if (JsonUtils.jsonElementExist(response, "solutions.placementSolutions")) {
335                 placements = jsonUtil.getJsonValue(response, "solutions.placementSolutions")
336                 if (isBlank(placements) || placements.equalsIgnoreCase("[]")) {
337                     String statusMessage = jsonUtil.getJsonValue(response, "statusMessage")
338                     if (isBlank(statusMessage)) {
339                         utils.log("DEBUG", "Error Occurred in Homing: OOF Async Callback Response does " +
340                                 "not contain placement solution.", isDebugEnabled)
341                         exceptionUtil.buildAndThrowWorkflowException(execution, 400,
342                                 "OOF Async Callback Response does not contain placement solution.")
343                     } else {
344                         utils.log("DEBUG", "Error Occurred in Homing: " + statusMessage, isDebugEnabled)
345                         exceptionUtil.buildAndThrowWorkflowException(execution, 400, statusMessage)
346                     }
347                 } else {
348                     return
349                 }
350             } else if (response.contains("error") || response.contains("Error") ) {
351                 String errorMessage = ""
352                 if (response.contains("policyException")) {
353                     String text = jsonUtil.getJsonValue(response, "requestError.policyException.text")
354                     errorMessage = "OOF Async Callback Response contains a Request Error Policy Exception: " + text
355                 } else if (response.contains("Unable to find any candidate for demand")) {
356                     errorMessage = "OOF Async Callback Response contains error: Unable to find any candidate for " +
357                             "demand *** Response: " + response.toString()
358                 } else if (response.contains("serviceException")) {
359                     String text = jsonUtil.getJsonValue(response, "requestError.serviceException.text")
360                     errorMessage = "OOF Async Callback Response contains a Request Error Service Exception: " + text
361                 } else {
362                     errorMessage = "OOF Async Callback Response contains a Request Error. Unable to determine the Request Error Exception."
363                 }
364                 utils.log("DEBUG", "Error Occurred in Homing: " + errorMessage, isDebugEnabled)
365                 exceptionUtil.buildAndThrowWorkflowException(execution, 400, errorMessage)
366
367             } else {
368                 utils.log("DEBUG", "Error Occurred in Homing: Received an Unknown Async Callback Response from OOF.", isDebugEnabled)
369                 exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Received an Unknown Async Callback Response from OOF.")
370             }
371         }
372
373     }
374
375     /**
376      * This method creates candidates json for placement Demands.
377      *
378      * @param execution
379      * @param existingCandidates -
380      * @param excludedCandidates -
381      * @param requiredCandidates -
382      *
383      * @return candidatesJson - a JSON string with candidates
384      */
385     String createCandidateJson(ArrayList existingCandidates = null,
386                                ArrayList excludedCandidates = null,
387                                ArrayList requiredCandidates = null) {
388         def candidatesJson = ""
389         def type = ""
390         if (existingCandidates != null && existingCandidates != {}) {
391             sb = new StringBuilder()
392             sb.append(",\n" +
393                     "  \"existingCandidates\": [\n")
394             def existingCandidateJson = ""
395             existingCandidates.each { existingCandidate ->
396                 type = existingCandidate.get('identifierType')
397                 if (type == 'vimId') {
398                     def cloudOwner = existingCandidate.get('cloudOwner')
399                     def cloudRegionId = existingCandidate.get('identifiers')
400                     existingCandidateJson = "{\n" +
401                             "    \"identifierType\": \"vimId\",\n" +
402                             "    \"cloudOwner\": \"${cloudOwner}\",\n" +
403                             "    \"identifiers\": [\"${cloudRegionId}\"]\n" +
404                             "    },"
405                     sb.append(existingCandidateJson)
406                 }
407                 if (type == 'serviceInstanceId') {
408                     def serviceInstanceId = existingCandidate.get('identifiers')
409                     existingCandidateJson += "{\n" +
410                             "    \"identifierType\": \"serviceInstanceId\",\n" +
411                             "    \"identifiers\": [\"${serviceInstanceId}\"]\n" +
412                             "    },"
413                     sb.append(existingCandidateJson)
414                 }
415             }
416             if (existingCandidateJson != "") {
417                 sb.setLength(sb.length() - 1)
418                 candidatesJson = sb.append(",\n],")
419             }
420         }
421         if (excludedCandidates != null && excludedCandidates != {}) {
422             sb = new StringBuilder()
423             sb.append(",\n" +
424                     "  \"excludedCandidates\": [\n")
425             def excludedCandidateJson = ""
426             excludedCandidates.each { excludedCandidate ->
427                 type = excludedCandidate.get('identifierType')
428                 if (type == 'vimId') {
429                     def cloudOwner = excludedCandidate.get('cloudOwner')
430                     def cloudRegionId = excludedCandidate.get('identifiers')
431                     excludedCandidateJson = "{\n" +
432                             "    \"identifierType\": \"vimId\",\n" +
433                             "    \"cloudOwner\": \"${cloudOwner}\",\n" +
434                             "    \"identifiers\": [\"${cloudRegionId}\"]\n" +
435                             "    },"
436                     sb.append(excludedCandidateJson)
437                 }
438                 if (type == 'serviceInstanceId') {
439                     def serviceInstanceId = excludedCandidate.get('identifiers')
440                     excludedCandidateJson += "{\n" +
441                             "    \"identifierType\": \"serviceInstanceId\",\n" +
442                             "    \"identifiers\": [\"${serviceInstanceId}\"]\n" +
443                             "    },"
444                     sb.append(excludedCandidateJson)
445                 }
446             }
447             if (excludedCandidateJson != "") {
448                 sb.setLength(sb.length() - 1)
449                 candidatesJson = sb.append(",\n],")
450             }
451         }
452         if (requiredCandidates != null && requiredCandidates != {}) {
453             sb = new StringBuilder()
454             sb.append(",\n" +
455                     "  \"requiredCandidates\": [\n")
456             def requiredCandidatesJson = ""
457             requiredCandidates.each { requiredCandidate ->
458                 type = requiredCandidate.get('identifierType')
459                 if (type == 'vimId') {
460                     def cloudOwner = requiredCandidate.get('cloudOwner')
461                     def cloudRegionId = requiredCandidate.get('identifiers')
462                     requiredCandidatesJson = "{\n" +
463                             "    \"identifierType\": \"vimId\",\n" +
464                             "    \"cloudOwner\": \"${cloudOwner}\",\n" +
465                             "    \"identifiers\": [\"${cloudRegionId}\"]\n" +
466                             "    },"
467                     sb.append(requiredCandidatesJson)
468                 }
469                 if (type == 'serviceInstanceId') {
470                     def serviceInstanceId = requiredCandidate.get('identifiers')
471                     requiredCandidatesJson += "{\n" +
472                             "    \"identifierType\": \"serviceInstanceId\",\n" +
473                             "    \"identifiers\": [\"${serviceInstanceId}\"]\n" +
474                             "    },"
475                     sb.append(requiredCandidatesJson)
476                 }
477             }
478             if (requiredCandidatesJson != "") {
479                 sb.setLength(sb.length() - 1)
480                 candidatesJson = sb.append(",\n],")
481             }
482         }
483         if (candidatesJson != "") {candidatesJson = candidatesJson.substring(0, candidatesJson.length() - 1)}
484         return candidatesJson
485     }
486
487     /**
488      * This method creates a cloudsite in catalog database.
489      *
490      * @param CloudSite cloudSite
491      *
492      * @return void
493      */
494     Void createCloudSite(CloudSite cloudSite, DelegateExecution execution) {
495         oofInfraUtils.createCloudSite(cloudSite, execution)
496     }
497
498     /**
499      * This method creates a HomingInstance in catalog database.
500      *
501      * @param HomingInstance homingInstance
502      *
503      * @return void
504      */
505     Void createHomingInstance(HomingInstance homingInstance, DelegateExecution execution) {
506         oofInfraUtils.createHomingInstance(homingInstance, execution)
507     }
508
509      String getMsbHost(DelegateExecution execution) {
510          String msbHost = UrnPropertiesReader.getVariable("mso.msb.host", execution, "msb-iag.onap")
511
512          Integer msbPort = UrnPropertiesReader.getVariable("mso.msb.port", execution, "80").toInteger()
513
514          return UriBuilder.fromPath("").host(msbHost).port(msbPort).scheme("http").build().toString()
515     }
516 }