2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.so.bpmn.common.scripts
22 import org.camunda.bpm.engine.delegate.BpmnError
23 import org.camunda.bpm.engine.delegate.DelegateExecution
24 import org.onap.so.bpmn.core.UrnPropertiesReader;
25 import org.onap.so.rest.APIResponse;
26 import org.onap.so.rest.RESTClient
27 import org.onap.so.rest.RESTConfig
28 import org.onap.so.logger.MessageEnum
29 import org.onap.so.logger.MsoLogger
34 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, AaiUtil.class);
37 public MsoUtils utils = new MsoUtils()
38 public static final String AAI_NAMESPACE_STRING_KEY = 'mso.workflow.global.default.aai.namespace'
39 public static final String DEFAULT_VERSION_KEY = 'mso.workflow.global.default.aai.version'
41 private String aaiNamespace = null;
43 private AbstractServiceTaskProcessor taskProcessor
45 public AaiUtil(AbstractServiceTaskProcessor taskProcessor) {
46 this.taskProcessor = taskProcessor
49 public String getNetworkGenericVnfEndpoint(DelegateExecution execution) {
50 String endpoint = UrnPropertiesReader.getVariable("aai.endpoint", execution)
51 def uri = getNetworkGenericVnfUri(execution)
52 msoLogger.debug('AaiUtil.getNetworkGenericVnfEndpoint() - AAI endpoint: ' + endpoint + uri)
56 public String getNetworkGenericVnfUri(DelegateExecution execution) {
57 def uri = getUri(execution, 'generic-vnf')
58 msoLogger.debug('AaiUtil.getNetworkGenericVnfUri() - AAI URI: ' + uri)
62 public String getNetworkVpnBindingUri(DelegateExecution execution) {
63 def uri = getUri(execution, 'vpn-binding')
64 msoLogger.debug('AaiUtil.getNetworkVpnBindingUri() - AAI URI: ' + uri)
68 public String getNetworkPolicyUri(DelegateExecution execution) {
69 def uri = getUri(execution, 'network-policy')
70 msoLogger.debug('AaiUtil.getNetworkPolicyUri() - AAI URI: ' + uri)
74 public String getNetworkTableReferencesUri(DelegateExecution execution) {
75 def uri = getUri(execution, 'route-table-reference')
76 msoLogger.debug('AaiUtil.getNetworkTableReferencesUri() - AAI URI: ' + uri)
80 public String getNetworkVceUri(DelegateExecution execution) {
81 def uri = getUri(execution, 'vce')
82 msoLogger.debug('AaiUtil.getNetworkVceUri() - AAI URI: ' + uri)
86 public String getNetworkL3NetworkUri(DelegateExecution execution) {
87 def uri = getUri(execution, 'l3-network')
88 msoLogger.debug('AaiUtil.getNetworkL3NetworkUri() - AAI URI: ' + uri)
92 public String getBusinessCustomerUri(DelegateExecution execution) {
93 def uri = getUri(execution, 'customer')
94 msoLogger.debug('AaiUtil.getBusinessCustomerUri() - AAI URI: ' + uri)
98 //public String getBusinessCustomerUriv7(DelegateExecution execution) {
99 // // //def uri = getUri(execution, BUSINESS_CUSTOMERV7)
100 // def uri = getUri(execution, 'Customer')
101 // msoLogger.debug('AaiUtil.getBusinessCustomerUriv7() - AAI URI: ' + uri)
105 public String getCloudInfrastructureCloudRegionEndpoint(DelegateExecution execution) {
106 String endpoint = UrnPropertiesReader.getVariable("aai.endpoint", execution)
107 def uri = getCloudInfrastructureCloudRegionUri(execution)
108 msoLogger.debug('AaiUtil.getCloudInfrastructureCloudRegionEndpoint() - AAI endpoint: ' + endpoint + uri)
109 return endpoint + uri
112 public String getCloudInfrastructureCloudRegionUri(DelegateExecution execution) {
113 def uri = getUri(execution, 'cloud-region')
114 msoLogger.debug('AaiUtil.getCloudInfrastructureCloudRegionUri() - AAI URI: ' + uri)
118 public String getCloudInfrastructureTenantUri(DelegateExecution execution) {
119 def uri = getUri(execution, 'tenant')
120 msoLogger.debug('AaiUtil.getCloudInfrastructureTenantUri() - AAI URI: ' + uri)
124 public String getSearchNodesQueryUri(DelegateExecution execution) {
125 def uri = getUri(execution, 'nodes-query')
126 msoLogger.debug('AaiUtil.getSearchNodesQueryUri() - AAI URI: ' + uri)
130 public String getSearchNodesQueryEndpoint(DelegateExecution execution) {
131 String endpoint = UrnPropertiesReader.getVariable("aai.endpoint", execution)
132 def uri = getSearchNodesQueryUri(execution)
133 msoLogger.debug('AaiUtil.getSearchNodesQueryEndpoint() - AAI endpoint: ' + endpoint + uri)
134 return endpoint + uri
137 public String getSearchGenericQueryUri(DelegateExecution execution) {
138 def uri = getUri(execution, 'generic-query')
139 msoLogger.debug('AaiUtil.getSearchGenericQueryUri() - AAI URI: ' + uri)
143 public String getVersion(DelegateExecution execution, resourceName, processKey) {
144 def versionWithResourceKey = "mso.workflow.default.aai.${resourceName}.version"
145 def versionWithProcessKey = "mso.workflow.custom.${processKey}.aai.version"
147 def version = UrnPropertiesReader.getVariable(versionWithProcessKey, execution)
149 msoLogger.debug("AaiUtil.getVersion() - using flow specific ${versionWithProcessKey}=${version}")
153 version = UrnPropertiesReader.getVariable(versionWithResourceKey, execution)
155 msoLogger.debug("AaiUtil.getVersion() - using resource specific ${versionWithResourceKey}=${version}")
159 version = UrnPropertiesReader.getVariable(DEFAULT_VERSION_KEY, execution)
161 msoLogger.debug("AaiUtil.getVersion() - using default version ${DEFAULT_VERSION_KEY}=${version}")
165 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, "Internal Error: One of the following should be defined in MSO URN properties file: ${versionWithResourceKey}, ${versionWithProcessKey}, ${DEFAULT_VERSION_KEY}")
168 public String getUri(DelegateExecution execution, resourceName) {
170 def processKey = taskProcessor.getMainProcessKey(execution)
173 setNamespace(execution)
175 // Check for flow+resource specific first
176 def key = "mso.workflow.${processKey}.aai.${resourceName}.uri"
177 def uri = UrnPropertiesReader.getVariable(key, execution)
179 msoLogger.debug("AaiUtil.getUri() - using flow+resource specific key: ${key}=${uri}")
183 // Check for versioned key
184 def version = getVersion(execution, resourceName, processKey)
185 key = "mso.workflow.default.aai.v${version}.${resourceName}.uri"
186 uri = UrnPropertiesReader.getVariable(key, execution)
189 msoLogger.debug("AaiUtil.getUri() - using versioned URI key: ${key}=${uri}")
193 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, 'Internal Error: AAI URI entry for ' + key + ' not defined in the MSO URN properties file')
196 public String setNamespace(DelegateExecution execution) {
197 def key = AAI_NAMESPACE_STRING_KEY
198 aaiNamespace = UrnPropertiesReader.getVariable(key, execution)
199 if (aaiNamespace == null ) {
200 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, 'Internal Error: AAI URI entry for ' + key + ' not defined in the MSO URN properties file')
205 * This method can be used for getting the building namespace out of uri.
206 * NOTE: A getUri() method needs to be invoked first.
207 * Alternative method is the getNamespaceFromUri(DelegateExecution execution, String uri)
208 * return namespace (plus version from uri)
215 public String getNamespaceFromUri(String uri) {
216 if (aaiNamespace == null) {
217 throw new Exception('Internal Error: AAI Namespace has not been set yet. A getUri() method needs to be invoked first.')
219 String namespace = aaiNamespace
221 String version = getVersionFromUri(uri)
222 return namespace + "v"+version
229 * This method can be used for building namespace with aai version out of uri.
230 * NOTE: 2 arguments: DelegateExecution execution & String uri
236 public String getNamespaceFromUri(DelegateExecution execution, String uri) {
237 String namespace = UrnPropertiesReader.getVariable(AAI_NAMESPACE_STRING_KEY, execution)
238 if (namespace == null ) {
239 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, 'Internal Error: AAI URI entry for ' + AAI_NAMESPACE_STRING_KEY + ' not defined in the MSO URN properties file')
242 String version = getVersionFromUri(uri)
243 return namespace + "v"+version
250 * This is used to extract the version from uri.
256 private String getVersionFromUri(String uri) {
258 def savedVersion = ""
259 for (int x=2; x<6; x++) {
260 version = uri.substring(uri.indexOf("v")+1, uri.indexOf("v")+x)
261 if (!Character.isDigit(version.charAt(version.size()-1))) {
264 savedVersion = version
271 * This reusable method can be used for making AAI Get Calls. The url should
272 * be passed as a parameter along with the execution. The method will
273 * return an APIResponse.
278 * @return APIResponse
281 public APIResponse executeAAIGetCall(DelegateExecution execution, String url){
282 msoLogger.trace("STARTED Execute AAI Get Process ")
283 APIResponse apiResponse = null
285 String uuid = utils.getRequestID()
286 msoLogger.debug("Generated uuid is: " + uuid)
287 msoLogger.debug("URL to be used is: " + url)
289 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
291 RESTConfig config = new RESTConfig(url);
292 RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml");
294 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
295 client.addAuthorizationHeader(basicAuthCred)
297 apiResponse = client.get()
299 msoLogger.trace("COMPLETED Execute AAI Get Process ")
301 msoLogger.debug("Exception occured while executing AAI Get Call. Exception is: \n" + e)
302 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
309 * This reusable method can be used for making AAI httpPut Calls. The url should
310 * be passed as a parameter along with the execution and payload. The method will
311 * return an APIResponse.
317 * @return APIResponse
320 public APIResponse executeAAIPutCall(DelegateExecution execution, String url, String payload){
321 msoLogger.trace("Started Execute AAI Put Process ")
322 APIResponse apiResponse = null
324 String uuid = utils.getRequestID()
325 msoLogger.debug("Generated uuid is: " + uuid)
326 msoLogger.debug("URL to be used is: " + url)
328 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
330 RESTConfig config = new RESTConfig(url);
331 RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Content-Type", "application/xml").addHeader("Accept","application/xml");
332 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
333 client.addAuthorizationHeader(basicAuthCred)
335 apiResponse = client.httpPut(payload)
337 msoLogger.trace("Completed Execute AAI Put Process ")
339 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Put Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
340 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
346 * This reusable method can be used for making AAI httpPatch Calls. The url should
347 * be passed as a parameter along with the execution and payload. The method will
348 * return an APIResponse.
354 * @return APIResponse
357 public APIResponse executeAAIPatchCall(DelegateExecution execution, String url, String payload){
358 msoLogger.trace("Started Execute AAI Patch Process ")
359 APIResponse apiResponse = null
361 String uuid = utils.getRequestID()
362 msoLogger.debug("Generated uuid is: " + uuid)
364 msoLogger.debug("URL to be used is: " + url)
366 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
368 RESTConfig config = new RESTConfig(url);
369 RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Content-Type", "application/merge-patch+json").addHeader("Accept","application/json");
370 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
371 client.addAuthorizationHeader(basicAuthCred)
373 apiResponse = client.httpPatch(payload)
375 msoLogger.trace("Completed Execute AAI Patch Process ")
377 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Patch Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
378 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
385 * This reusable method can be used for making AAI Delete Calls. The url should
386 * be passed as a parameter along with the execution. The method will
387 * return an APIResponse.
392 * @return APIResponse
395 public APIResponse executeAAIDeleteCall(DelegateExecution execution, String url){
396 msoLogger.trace("Started Execute AAI Delete Process ")
397 APIResponse apiResponse = null
399 String uuid = utils.getRequestID()
400 msoLogger.debug("Generated uuid is: " + uuid)
401 msoLogger.debug("URL to be used is: " + url)
403 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
405 RESTConfig config = new RESTConfig(url);
406 RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml");
407 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
408 client.addAuthorizationHeader(basicAuthCred)
410 apiResponse = client.delete()
412 msoLogger.trace("Completed Execute AAI Delete Process ")
414 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Delete Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
415 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
421 * This reusable method can be used for making AAI Delete Calls. The url should
422 * be passed as a parameter along with the execution. The method will
423 * return an APIResponse.
429 * @return APIResponse
432 public APIResponse executeAAIDeleteCall(DelegateExecution execution, String url, String payload, String authHeader){
433 msoLogger.trace("Started Execute AAI Delete Process ")
434 APIResponse apiResponse = null
436 String uuid = utils.getRequestID()
437 msoLogger.debug("Generated uuid is: " + uuid)
439 msoLogger.debug("URL to be used is: " + url)
441 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
442 RESTConfig config = new RESTConfig(url);
443 RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml").addAuthorizationHeader(authHeader);
444 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
445 client.addAuthorizationHeader(basicAuthCred)
447 apiResponse = client.httpDelete(payload)
449 msoLogger.trace("Completed Execute AAI Delete Process ")
451 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Delete Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
452 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
458 * This reusable method can be used for making AAI Post Calls. The url
459 * and payload should be passed as a parameters along with the execution.
460 * The method will return an APIResponse.
466 * @return APIResponse
469 public APIResponse executeAAIPostCall(DelegateExecution execution, String url, String payload){
470 msoLogger.trace("Started Execute AAI Post Process ")
471 APIResponse apiResponse = null
473 String uuid = utils.getRequestID()
474 msoLogger.debug("Generated uuid is: " + uuid)
475 msoLogger.debug("URL to be used is: " + url)
477 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
478 RESTConfig config = new RESTConfig(url);
479 RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml");
481 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
482 client.addAuthorizationHeader(basicAuthCred)
484 apiResponse = client.httpPost(payload)
486 msoLogger.trace("Completed Execute AAI Post Process ")
488 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Post Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
489 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
495 * This reusable method can be used for making AAI Post Calls. The url
496 * and payload should be passed as a parameters along with the execution.
497 * The method will return an APIResponse.
502 * @param authenticationHeader - addAuthenticationHeader value
503 * @param headerName - name of header you want to add, i.e. addHeader(headerName, headerValue)
504 * @param headerValue - the header's value, i.e. addHeader(headerName, headerValue)
506 * @return APIResponse
509 public APIResponse executeAAIPostCall(DelegateExecution execution, String url, String payload, String authenticationHeaderValue, String headerName, String headerValue){
510 msoLogger.trace("Started Execute AAI Post Process ")
511 APIResponse apiResponse = null
513 msoLogger.debug("URL to be used is: " + url)
515 String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
517 RESTConfig config = new RESTConfig(url);
518 RESTClient client = new RESTClient(config).addAuthorizationHeader(authenticationHeaderValue).addHeader(headerName, headerValue)
519 if (basicAuthCred != null && !"".equals(basicAuthCred)) {
520 client.addAuthorizationHeader(basicAuthCred)
522 apiResponse = client.httpPost(payload)
524 msoLogger.trace("Completed Execute AAI Post Process ")
526 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Post Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
527 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
533 /* Utility to get the Cloud Region from AAI
534 * Returns String cloud region id, (ie, cloud-region-id)
536 * @param url - url for AAI get cloud region
537 * @param backend - "PO" - real region, or "SDNC" - v2.5 (fake region).
540 public String getAAICloudReqion(DelegateExecution execution, String url, String backend, inputCloudRegion){
543 APIResponse apiResponse = executeAAIGetCall(execution, url)
544 String returnCode = apiResponse.getStatusCode()
545 String aaiResponseAsString = apiResponse.getResponseBodyAsString()
546 msoLogger.debug("Call AAI Cloud Region Return code: " + returnCode)
547 execution.setVariable(execution.getVariable("prefix")+"queryCloudRegionReturnCode", returnCode)
549 if(returnCode == "200"){
550 msoLogger.debug("Call AAI Cloud Region is Successful.")
552 String regionVersion = taskProcessor.utils.getNodeText(aaiResponseAsString, "cloud-region-version")
553 msoLogger.debug("Cloud Region Version from AAI for " + backend + " is: " + regionVersion)
554 if (backend == "PO") {
555 regionId = taskProcessor.utils.getNodeText(aaiResponseAsString, "cloud-region-id")
556 } else { // backend not "PO"
557 if (regionVersion == "2.5" ) {
558 regionId = "AAIAIC25"
560 regionId = taskProcessor.utils.getNodeText(aaiResponseAsString, "cloud-region-id")
563 if(regionId == null){
564 throw new BpmnError("MSOWorkflowException")
566 msoLogger.debug("Cloud Region Id from AAI " + backend + " is: " + regionId)
567 }else if (returnCode == "404"){ // not 200
568 if (backend == "PO") {
569 regionId = inputCloudRegion
570 }else{ // backend not "PO"
571 regionId = "AAIAIC25"
573 msoLogger.debug("Cloud Region value for code='404' of " + backend + " is: " + regionId)
575 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Call AAI Cloud Region is NOT Successful.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
576 throw new BpmnError("MSOWorkflowException")
578 }catch(Exception e) {
579 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while getting the Cloud Reqion.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e.getMessage());
580 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
585 /* returns xml Node with service-type of searchValue */
586 def searchServiceType(xmlInput, searchValue){
587 def fxml= new XmlSlurper().parseText(xmlInput)
588 def ret = fxml.'**'.find {it.'service-type' == searchValue}
592 /* returns xml Node with service-instance-id of searchValue */
593 def searchServiceInstanceId(xmlInput, searchValue){
594 def ret = xmlInput.'**'.find {it.'service-instance-id' == searchValue}
599 * Get the lowest unused VF Module index from AAI response for a given module type. The criteria for
600 * determining module type is specified by "key" parameter (for example, "persona-model-id"),
601 * the value for filtering is specified in "value" parameter
604 * @param aaiVnfResponse
608 * @return moduleIndex
611 public int getLowestUnusedVfModuleIndexFromAAIVnfResponse(DelegateExecution execution, String aaiVnfResponse, String key, String value) {
612 if (aaiVnfResponse != null) {
613 String vfModulesText = taskProcessor.utils.getNodeXml(aaiVnfResponse, "vf-modules")
614 if (vfModulesText == null || vfModulesText.isEmpty()) {
615 msoLogger.debug("There are no VF modules in this VNF yet")
619 def xmlVfModules= new XmlSlurper().parseText(vfModulesText)
620 def vfModules = xmlVfModules.'**'.findAll {it.name() == "vf-module"}
621 int vfModulesSize = 0
622 if (vfModules != null) {
623 vfModulesSize = vfModules.size()
625 String matchingVfModules = "<vfModules>"
626 for (i in 0..vfModulesSize-1) {
627 def vfModuleXml = groovy.xml.XmlUtil.serialize(vfModules[i])
628 def keyFromAAI = taskProcessor.utils.getNodeText(vfModuleXml, key)
629 if (keyFromAAI != null && keyFromAAI.equals(value)) {
630 matchingVfModules = matchingVfModules + taskProcessor.utils.removeXmlPreamble(vfModuleXml)
633 matchingVfModules = matchingVfModules + "</vfModules>"
634 msoLogger.debug("Matching VF Modules: " + matchingVfModules)
635 String lowestUnusedIndex = taskProcessor.utils.getLowestUnusedIndex(matchingVfModules)
636 return Integer.parseInt(lowestUnusedIndex)