2f4e70c8930b9b5fb912d09ac0a3fbc9f18b810d
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / AaiUtil.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.common.scripts
22 import java.util.regex.Matcher
23 import java.util.regex.Pattern
24
25 import javax.ws.rs.core.UriBuilder
26
27 import org.camunda.bpm.engine.delegate.BpmnError
28 import org.camunda.bpm.engine.delegate.DelegateExecution
29 import org.onap.so.bpmn.core.UrnPropertiesReader;
30 import org.onap.so.client.aai.AAIVersion
31 import org.onap.so.client.aai.entities.uri.AAIUri
32 import org.onap.so.logger.MessageEnum
33 import org.onap.so.logger.MsoLogger
34 import org.onap.so.openpojo.rules.HasToStringRule
35 import org.onap.so.rest.APIResponse;
36 import org.onap.so.rest.RESTClient
37 import org.onap.so.rest.RESTConfig
38
39 @Deprecated
40 class AaiUtil {
41         private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, AaiUtil.class);
42
43
44         public MsoUtils utils = new MsoUtils()
45         public static final String AAI_NAMESPACE_STRING_KEY = 'mso.workflow.global.default.aai.namespace'
46         public static final String DEFAULT_VERSION_KEY = 'mso.workflow.global.default.aai.version'
47
48         private String aaiNamespace = null;
49
50         private AbstractServiceTaskProcessor taskProcessor
51
52         public AaiUtil(AbstractServiceTaskProcessor taskProcessor) {
53                 this.taskProcessor = taskProcessor
54         }
55
56         public String getBusinessSPPartnerUri(DelegateExecution execution) {
57                 def uri = getUri(execution, 'sp-partner')
58                 msoLogger.debug('AaiUtil.getBusinessSPPartnerUri() - AAI URI: ' + uri)
59                 return uri
60         }
61
62         public String getVersion(DelegateExecution execution, resourceName, processKey) {
63                 def versionWithResourceKey = "mso.workflow.default.aai.${resourceName}.version"
64                 def versionWithProcessKey = "mso.workflow.custom.${processKey}.aai.version"
65
66                 def version = UrnPropertiesReader.getVariable(versionWithProcessKey, execution)
67                 if (version) {
68                         msoLogger.debug("AaiUtil.getVersion() - using flow specific ${versionWithProcessKey}=${version}")
69                         return version
70                 }
71
72                 version = UrnPropertiesReader.getVariable(versionWithResourceKey, execution)
73                 if (version) {
74                         msoLogger.debug("AaiUtil.getVersion() - using resource specific ${versionWithResourceKey}=${version}")
75                         return version
76                 }
77
78                 version = UrnPropertiesReader.getVariable(DEFAULT_VERSION_KEY, execution)
79                 if (version) {
80                         msoLogger.debug("AaiUtil.getVersion() - using default version ${DEFAULT_VERSION_KEY}=${version}")
81                         return version
82                 }
83
84                 (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, "Internal Error: One of the following should be defined in MSO URN properties file: ${versionWithResourceKey}, ${versionWithProcessKey}, ${DEFAULT_VERSION_KEY}")
85         }
86
87         public String createAaiUri(AAIUri uri) {
88                 return createAaiUri(AAIVersion.valueOf('V' + UrnPropertiesReader.getVariable(DEFAULT_VERSION_KEY)), uri)
89         }
90         public String createAaiUri(AAIVersion version, AAIUri uri) {
91                 String endpoint = UrnPropertiesReader.getVariable("aai.endpoint")
92                 String result = UriBuilder.fromUri(endpoint).path('aai').path(version.toString()).build().toString()
93                 return UriBuilder.fromUri(result + uri.build().toString()).build().toString()
94         }
95
96         public String setNamespace(DelegateExecution execution) {
97                 def key = AAI_NAMESPACE_STRING_KEY
98                 aaiNamespace = UrnPropertiesReader.getVariable(key, execution)
99                 if (aaiNamespace == null ) {
100                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, 'Internal Error: AAI URI entry for ' + key + ' not defined in the MSO URN properties file')
101                 }
102         }
103
104         public String getNamespace() {
105                 return getNamespace(AAIVersion.valueOf('V' + UrnPropertiesReader.getVariable(DEFAULT_VERSION_KEY)))
106         }
107
108         public String getNamespace(AAIVersion version) {
109                 String namespace = UrnPropertiesReader.getVariable(AAI_NAMESPACE_STRING_KEY)
110                 if (namespace == null) {
111                    throw new Exception('Internal Error: AAI Namespace has not been set yet. A getUri() method needs to be invoked first.')
112                 }
113
114                 return namespace + version
115         }
116         /**
117          * This method can be used for getting the building namespace out of uri.
118          *  NOTE: A getUri() method needs to be invoked first.
119          *        Alternative method is the getNamespaceFromUri(DelegateExecution execution, String uri)
120          * return namespace (plus version from uri)
121          *
122          * @param url
123          *
124          * @return namespace
125          */
126         public String getNamespaceFromUri(String uri) {
127                 String namespace = UrnPropertiesReader.getVariable(AAI_NAMESPACE_STRING_KEY)
128                  if (namespace == null) {
129                         throw new Exception('Internal Error: AAI Namespace has not been set yet. A getUri() method needs to be invoked first.')
130                 }
131                 if(uri!=null){
132                         String version = getVersionFromUri(uri)
133                         return namespace + "v"+version
134                 }else{
135                         return namespace
136                 }
137         }
138
139         /**
140          * This method can be used for building namespace with aai version out of uri.
141          *   NOTE: 2 arguments: DelegateExecution execution & String uri
142          * @param execution
143          * @param url
144          *
145          * @return namespace
146          */
147         public String getNamespaceFromUri(DelegateExecution execution, String uri) {
148            String namespace = UrnPropertiesReader.getVariable(AAI_NAMESPACE_STRING_KEY, execution)
149            if (namespace == null ) {
150                    (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, 'Internal Error: AAI URI entry for ' + AAI_NAMESPACE_STRING_KEY + ' not defined in the MSO URN properties file')
151            }
152            if(uri!=null){
153                    String version = getVersionFromUri(uri)
154                    return namespace + "v"+version
155            }else{
156                    return namespace
157            }
158    }
159
160         /**
161          * This is used to extract the version from uri.
162          *
163          * @param uri
164          *
165          * @return version
166          */
167         private String getVersionFromUri(String uri) {
168
169                 Matcher versionRegEx = Pattern.compile("/v(\\d+)").matcher(uri)
170                 if (versionRegEx.find()) {
171                         return versionRegEx.group(1);
172                 }
173
174                 return "";
175         }
176
177
178         /**
179          * This reusable method can be used for making AAI Get Calls. The url should
180          * be passed as a parameter along with the execution.  The method will
181          * return an APIResponse.
182          *
183          * @param execution
184          * @param url
185          *
186          * @return APIResponse
187          *
188          */
189         public APIResponse executeAAIGetCall(DelegateExecution execution, String url){
190                 msoLogger.trace("STARTED Execute AAI Get Process ")
191                 APIResponse apiResponse = null
192                 try{
193                         String uuid = utils.getRequestID()
194                         msoLogger.debug("Generated uuid is: " + uuid)
195                         msoLogger.debug("URL to be used is: " + url)
196
197                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
198
199                         RESTConfig config = new RESTConfig(url);
200                         RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml");
201
202                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
203                                 client.addAuthorizationHeader(basicAuthCred)
204                         }
205                         apiResponse = client.httpGet()
206
207                         msoLogger.trace("COMPLETED Execute AAI Get Process ")
208                 }catch(Exception e){
209                         msoLogger.debug("Exception occured while executing AAI Get Call. Exception is: \n" + e)
210                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
211                 }
212                 return apiResponse
213         }
214
215
216         /**
217          * This reusable method can be used for making AAI httpPut Calls. The url should
218          * be passed as a parameter along with the execution and payload.  The method will
219          * return an APIResponse.
220          *
221          * @param execution
222          * @param url
223          * @param payload
224          *
225          * @return APIResponse
226          *
227          */
228         public APIResponse executeAAIPutCall(DelegateExecution execution, String url, String payload){
229                 msoLogger.trace("Started Execute AAI Put Process ")
230                 APIResponse apiResponse = null
231                 try{
232                         String uuid = utils.getRequestID()
233                         msoLogger.debug("Generated uuid is: " + uuid)
234                         msoLogger.debug("URL to be used is: " + url)
235
236                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
237
238                         RESTConfig config = new RESTConfig(url);
239                         RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Content-Type", "application/xml").addHeader("Accept","application/xml");
240                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
241                                 client.addAuthorizationHeader(basicAuthCred)
242                         }
243                         apiResponse = client.httpPut(payload)
244
245                         msoLogger.trace("Completed Execute AAI Put Process ")
246                 }catch(Exception e){
247                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Put Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
248                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
249                 }
250                 return apiResponse
251         }
252
253         /**
254          * This reusable method can be used for making AAI httpPatch Calls. The url should
255          * be passed as a parameter along with the execution and payload.  The method will
256          * return an APIResponse.
257          *
258          * @param execution
259          * @param url
260          * @param payload
261          *
262          * @return APIResponse
263          *
264          */
265         public APIResponse executeAAIPatchCall(DelegateExecution execution, String url, String payload){
266                 msoLogger.trace("Started Execute AAI Patch Process ")
267                 APIResponse apiResponse = null
268                 try{
269                         String uuid = utils.getRequestID()
270                         msoLogger.debug("Generated uuid is: " + uuid)
271
272                         msoLogger.debug("URL to be used is: " + url)
273
274                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
275
276                         RESTConfig config = new RESTConfig(url);
277                         RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Content-Type", "application/merge-patch+json").addHeader("Accept","application/json");
278                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
279                                 client.addAuthorizationHeader(basicAuthCred)
280                         }
281                         apiResponse = client.httpPatch(payload)
282
283                         msoLogger.trace("Completed Execute AAI Patch Process ")
284                 }catch(Exception e){
285                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Patch Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
286                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
287                 }
288                 return apiResponse
289         }
290
291
292         /**
293          * This reusable method can be used for making AAI Delete Calls. The url should
294          * be passed as a parameter along with the execution.  The method will
295          * return an APIResponse.
296          *
297          * @param execution
298          * @param url
299          *
300          * @return APIResponse
301          *
302          */
303         public APIResponse executeAAIDeleteCall(DelegateExecution execution, String url){
304                 msoLogger.trace("Started Execute AAI Delete Process ")
305                 APIResponse apiResponse = null
306                 try{
307                         String uuid = utils.getRequestID()
308                         msoLogger.debug("Generated uuid is: " + uuid)
309                         msoLogger.debug("URL to be used is: " + url)
310
311                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
312
313                         RESTConfig config = new RESTConfig(url);
314                         RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml");
315                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
316                                 client.addAuthorizationHeader(basicAuthCred)
317                         }
318                         apiResponse = client.delete()
319
320                         msoLogger.trace("Completed Execute AAI Delete Process ")
321                 }catch(Exception e){
322                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Delete Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
323                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
324                 }
325                 return apiResponse
326         }
327
328         /**
329          * This reusable method can be used for making AAI Delete Calls. The url should
330          * be passed as a parameter along with the execution.  The method will
331          * return an APIResponse.
332          *
333          * @param execution
334          * @param url
335          * @param payload
336          *
337          * @return APIResponse
338          *
339          */
340         public APIResponse executeAAIDeleteCall(DelegateExecution execution, String url, String payload, String authHeader){
341                 msoLogger.trace("Started Execute AAI Delete Process ")
342                 APIResponse apiResponse = null
343                 try{
344                         String uuid = utils.getRequestID()
345                         msoLogger.debug("Generated uuid is: " + uuid)
346
347                         msoLogger.debug("URL to be used is: " + url)
348
349                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
350                         RESTConfig config = new RESTConfig(url);
351                         RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml").addAuthorizationHeader(authHeader);
352                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
353                                 client.addAuthorizationHeader(basicAuthCred)
354                         }
355                         apiResponse = client.httpDelete(payload)
356
357                         msoLogger.trace("Completed Execute AAI Delete Process ")
358                 }catch(Exception e){
359                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Delete Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
360                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
361                 }
362                 return apiResponse
363         }
364
365         /**
366          * This reusable method can be used for making AAI Post Calls. The url
367          * and payload should be passed as a parameters along with the execution.
368          * The method will return an APIResponse.
369          *
370          * @param execution
371          * @param url
372          * @param payload
373          *
374          * @return APIResponse
375          *
376          */
377         public APIResponse executeAAIPostCall(DelegateExecution execution, String url, String payload){
378                 msoLogger.trace("Started Execute AAI Post Process ")
379                 APIResponse apiResponse = null
380                 try{
381                         String uuid = utils.getRequestID()
382                         msoLogger.debug("Generated uuid is: " + uuid)
383                         msoLogger.debug("URL to be used is: " + url)
384
385                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
386                         RESTConfig config = new RESTConfig(url);
387                         RESTClient client = new RESTClient(config).addHeader("X-FromAppId", "MSO").addHeader("X-TransactionId", uuid).addHeader("Accept","application/xml");
388
389                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
390                                 client.addAuthorizationHeader(basicAuthCred)
391                         }
392                         apiResponse = client.httpPost(payload)
393
394                         msoLogger.trace("Completed Execute AAI Post Process ")
395                 }catch(Exception e){
396                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Post Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
397                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
398                 }
399                 return apiResponse
400         }
401
402         /**
403          * This reusable method can be used for making AAI Post Calls. The url
404          * and payload should be passed as a parameters along with the execution.
405          * The method will return an APIResponse.
406          *
407          * @param execution
408          * @param url
409          * @param payload
410          * @param authenticationHeader - addAuthenticationHeader value
411          * @param headerName - name of header you want to add, i.e. addHeader(headerName, headerValue)
412          * @param headerValue - the header's value, i.e. addHeader(headerName, headerValue)
413          *
414          * @return APIResponse
415          *
416          */
417         public APIResponse executeAAIPostCall(DelegateExecution execution, String url, String payload, String authenticationHeaderValue, String headerName, String headerValue){
418                 msoLogger.trace("Started Execute AAI Post Process ")
419                 APIResponse apiResponse = null
420                 try{
421                         msoLogger.debug("URL to be used is: " + url)
422
423                         String basicAuthCred = utils.getBasicAuth(UrnPropertiesReader.getVariable("aai.auth", execution),UrnPropertiesReader.getVariable("mso.msoKey", execution))
424
425                         RESTConfig config = new RESTConfig(url);
426                         RESTClient client = new RESTClient(config).addAuthorizationHeader(authenticationHeaderValue).addHeader(headerName, headerValue)
427                         if (basicAuthCred != null && !"".equals(basicAuthCred)) {
428                                 client.addAuthorizationHeader(basicAuthCred)
429                         }
430                         apiResponse = client.httpPost(payload)
431
432                         msoLogger.trace("Completed Execute AAI Post Process ")
433                 }catch(Exception e){
434                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while executing AAI Post Call.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e);
435                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
436                 }
437                 return apiResponse
438         }
439
440
441         /* Utility to get the Cloud Region from AAI
442          * Returns String cloud region id, (ie, cloud-region-id)
443          * @param execution
444          * @param url  - url for AAI get cloud region
445          * @param backend - "PO" - real region, or "SDNC" - v2.5 (fake region).
446          */
447
448         public String getAAICloudReqion(DelegateExecution execution, String url, String backend, inputCloudRegion){
449                 String regionId = ""
450                 try{
451                         APIResponse apiResponse = executeAAIGetCall(execution, url)
452                         String returnCode = apiResponse.getStatusCode()
453                         String aaiResponseAsString = apiResponse.getResponseBodyAsString()
454                         msoLogger.debug("Call AAI Cloud Region Return code: " + returnCode)
455                         execution.setVariable(execution.getVariable("prefix")+"queryCloudRegionReturnCode", returnCode)
456
457                         if(returnCode == "200"){
458                                 msoLogger.debug("Call AAI Cloud Region is Successful.")
459
460                                 String regionVersion = taskProcessor.utils.getNodeText(aaiResponseAsString, "cloud-region-version")
461                                 msoLogger.debug("Cloud Region Version from AAI for " + backend + " is: " + regionVersion)
462                                 if (backend == "PO") {
463                                         regionId = taskProcessor.utils.getNodeText(aaiResponseAsString, "cloud-region-id")
464                                 } else { // backend not "PO"
465                                         if (regionVersion == "2.5" ) {
466                                                 regionId = "AAIAIC25"
467                                         } else {
468                                                 regionId = taskProcessor.utils.getNodeText(aaiResponseAsString, "cloud-region-id")
469                                         }
470                                 }
471                                 if(regionId == null){
472                                         throw new BpmnError("MSOWorkflowException")
473                                 }
474                                 msoLogger.debug("Cloud Region Id from AAI " + backend + " is: " + regionId)
475                         }else if (returnCode == "404"){ // not 200
476                                 if (backend == "PO") {
477                                         regionId = inputCloudRegion
478                                 }else{  // backend not "PO"
479                                         regionId = "AAIAIC25"
480                                 }
481                                 msoLogger.debug("Cloud Region value for code='404' of " + backend + " is: " + regionId)
482                         }else{
483                                 msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Call AAI Cloud Region is NOT Successful.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, "");
484                                 throw new BpmnError("MSOWorkflowException")
485                         }
486                 }catch(Exception e) {
487                         msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, "Exception occured while getting the Cloud Reqion.", "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, e.getMessage());
488                         (new ExceptionUtil()).buildAndThrowWorkflowException(execution, 9999, e.getMessage())
489                 }
490                 return regionId
491         }
492
493         /* returns xml Node with service-type of searchValue */
494         def searchServiceType(xmlInput, searchValue){
495                 def fxml= new XmlSlurper().parseText(xmlInput)
496                 def ret = fxml.'**'.find {it.'service-type' == searchValue}
497                 return ret
498         }
499
500         /* returns xml Node with service-instance-id of searchValue */
501         def searchServiceInstanceId(xmlInput, searchValue){
502                 def ret = xmlInput.'**'.find {it.'service-instance-id' == searchValue}
503                 return ret
504         }
505
506         /**
507          * Get the lowest unused VF Module index from AAI response for a given module type. The criteria for
508          * determining module type is specified by "key" parameter (for example, "persona-model-id"),
509          * the value for filtering is specified in "value" parameter
510          *
511          * @param execution
512          * @param aaiVnfResponse
513          * @param key
514          * @param value
515          *
516          * @return moduleIndex
517          *
518          */
519         public int getLowestUnusedVfModuleIndexFromAAIVnfResponse(DelegateExecution execution, String aaiVnfResponse, String key, String value) {
520                 if (aaiVnfResponse != null) {
521                         String vfModulesText = taskProcessor.utils.getNodeXml(aaiVnfResponse, "vf-modules")
522                         if (vfModulesText == null || vfModulesText.isEmpty()) {
523                                 msoLogger.debug("There are no VF modules in this VNF yet")
524                                 return 0
525                         }
526                         else {
527                                 def xmlVfModules= new XmlSlurper().parseText(vfModulesText)
528                                 def vfModules = xmlVfModules.'**'.findAll {it.name() == "vf-module"}
529                                 int vfModulesSize = 0
530                                 if (vfModules != null) {
531                                         vfModulesSize = vfModules.size()
532                                 }
533                                 String matchingVfModules = "<vfModules>"
534                                 for (i in 0..vfModulesSize-1) {
535                                         def vfModuleXml = groovy.xml.XmlUtil.serialize(vfModules[i])
536                                         def keyFromAAI = taskProcessor.utils.getNodeText(vfModuleXml, key)
537                                         if (keyFromAAI != null && keyFromAAI.equals(value)) {
538                                                 matchingVfModules = matchingVfModules + taskProcessor.utils.removeXmlPreamble(vfModuleXml)
539                                         }
540                                 }
541                                 matchingVfModules = matchingVfModules + "</vfModules>"
542                                 msoLogger.debug("Matching VF Modules: " + matchingVfModules)
543                                 String lowestUnusedIndex = taskProcessor.utils.getLowestUnusedIndex(matchingVfModules)
544                                 return Integer.parseInt(lowestUnusedIndex)
545                         }
546                 }
547                 else {
548                         return 0
549                 }
550         }
551 }
552