Provide index token to tosca function for nested lists 91/134591/6
authorimamSidero <imam.hussain@est.tech>
Thu, 18 May 2023 16:56:32 +0000 (17:56 +0100)
committerimamSidero <imam.hussain@est.tech>
Mon, 22 May 2023 18:32:28 +0000 (19:32 +0100)
Index token capability is provided in tosca function for all nested levels of list and custom types

Issue-ID: SDC-4505
Signed-off-by: Imam hussain <imam.hussain@est.tech>
Change-Id: If21c0078e0d17c44b5a31b00d6fac3e18ff6831d

catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/ToscaFunctionYamlParsingHandler.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/validation/ToscaFunctionValidatorImpl.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/validation/ToscaFunctionValidatorImplTest.java
catalog-ui/src/app/models/tosca-get-function.ts
catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializer.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaGetFunctionDataDefinition.java
common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/ToscaGetFunctionDataDefinitionTest.java

index 80608a8..4060432 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.openecomp.sdc.be.components.csar;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -28,7 +29,6 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.openecomp.sdc.be.config.Configuration;
@@ -77,13 +77,27 @@ public class ToscaFunctionYamlParsingHandler {
             toscaGetFunction.setSourceName(propertySourceType);
         }
         List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
-        String toscaIndexValue = propertySourceIndex.get((propertySourceIndex.size() - 1));
-        if (propertySourceIndex.size() > 1 && (toscaIndexValue.equalsIgnoreCase("INDEX") || StringUtils.isNumeric(toscaIndexValue))) {
-            toscaGetFunction.setPropertyPathFromSource(propertySourceIndex.subList(0, (propertySourceIndex.size() - 1)));
-            toscaGetFunction.setToscaIndex(toscaIndexValue);
-        } else {
-            toscaGetFunction.setPropertyPathFromSource(propertySourceIndex);
+        List<String> propertySourcePath = new ArrayList<>();
+        propertySourcePath.add((String)propertySourceIndex.get(0));
+        if (propertySourceIndex.size() > 1 ) {
+            List<Object> indexParsedList = new ArrayList<Object>();
+            List<String> indexObjectList = propertySourceIndex.subList(1,propertySourceIndex.size());
+            boolean loopFlag = true;
+            for (String indexValue : indexObjectList) {
+                if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
+                    propertySourcePath.add(indexValue);
+                } else {
+                    loopFlag = false;
+                    if (StringUtils.isNumeric(indexValue)) {
+                        indexParsedList.add(Integer.parseInt(indexValue));
+                    } else {
+                        indexParsedList.add(indexValue);
+                    }
+                }
+            }
+            toscaGetFunction.setToscaIndexList(indexParsedList);
         }
+        toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
         toscaGetFunction.setPropertyName(propertyName);
         return Optional.of(toscaGetFunction);
@@ -108,13 +122,27 @@ public class ToscaFunctionYamlParsingHandler {
             } catch (final ClassCastException ignored) {
                 return Optional.empty();
             }
-            String toscaIndexValue = functionParameters.get((functionParameters.size() - 1));
-            if (functionParameters.size() > 1 && (toscaIndexValue.equalsIgnoreCase("INDEX") || StringUtils.isNumeric(toscaIndexValue))) {
-                toscaGetFunction.setPropertyPathFromSource(functionParameters.subList(0, (functionParameters.size() - 1)));
-                toscaGetFunction.setToscaIndex(toscaIndexValue);
-            } else {
-                toscaGetFunction.setPropertyPathFromSource(functionParameters);
+            List<String> propertySourcePath = new ArrayList<>();
+            propertySourcePath.add((String)functionParameters.get(0));
+            if (functionParameters.size() > 1 ) {
+                List<Object> indexParsedList = new ArrayList<Object>();
+                List<String> indexObjectList = functionParameters.subList(1,functionParameters.size());
+                boolean loopFlag = true;
+                for (String indexValue : indexObjectList) {
+                    if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
+                        propertySourcePath.add(indexValue);
+                    } else {
+                        loopFlag = false;
+                        if (StringUtils.isNumeric(indexValue)) {
+                            indexParsedList.add(Integer.parseInt(indexValue));
+                        } else {
+                            indexParsedList.add(indexValue);
+                        }
+                    }
+                }
+                toscaGetFunction.setToscaIndexList(indexParsedList);
             }
+            toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
         }
         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
         toscaGetFunction.setPropertyName(propertyName);
index 16ec9ad..c6007a3 100644 (file)
@@ -2547,7 +2547,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
             throw ToscaGetFunctionExceptionSupplier
                 .propertyTypeDiverge(toscaGetFunction.getType(), referredProperty.getType(), property.getType()).get();
         }
-        if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
+        if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getType()) && !"list".equalsIgnoreCase(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
             throw ToscaGetFunctionExceptionSupplier
                 .propertySchemaDiverge(toscaGetFunction.getType(), referredProperty.getSchemaType(), property.getSchemaType()).get();
         }
index 1e485d9..b76ae59 100644 (file)
@@ -133,7 +133,7 @@ public class ToscaFunctionValidatorImpl implements ToscaFunctionValidator {
             throw ToscaGetFunctionExceptionSupplier
                 .propertyTypeDiverge(toscaGetFunction.getType(), referredProperty.getType(), property.getType()).get();
         }
-        if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
+        if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getType()) && !"list".equalsIgnoreCase(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
             throw ToscaGetFunctionExceptionSupplier
                 .propertySchemaDiverge(toscaGetFunction.getType(), referredProperty.getSchemaType(), property.getSchemaType()).get();
         }
index 3b86d9d..5ff31ba 100644 (file)
@@ -283,7 +283,7 @@ class ToscaFunctionValidatorImplTest {
         final String inputId = String.format("%s.%s", containerComponentId, inputName);
         final String propertyName = "getInputProperty";
         final String propertyId = String.format("%s.%s", containerComponentId, propertyName);
-        final String propertyType = "list";
+        final String propertyType = "map";
         final ComponentInstanceProperty propertyGetInput = createComponentInstanceProperty(
             propertyId,
             "getInputProperty",
index 3bb2077..67d9b0a 100644 (file)
@@ -35,7 +35,7 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter {
     functionType: ToscaGetFunctionType;
     propertyPathFromSource: Array<string>;
     value: any;
-    toscaIndex: string;
+    toscaIndexList: Array<string>;
 
     constructor(toscaGetFunction?: ToscaGetFunction) {
         if (!toscaGetFunction) {
@@ -49,7 +49,7 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter {
         this.sourceUniqueId = toscaGetFunction.sourceUniqueId;
         this.sourceName = toscaGetFunction.sourceName;
         this.functionType = toscaGetFunction.functionType;
-        this.toscaIndex = toscaGetFunction.toscaIndex;
+        this.toscaIndexList = toscaGetFunction.toscaIndexList;
         if (toscaGetFunction.propertyPathFromSource) {
             this.propertyPathFromSource = [...toscaGetFunction.propertyPathFromSource];
         }
@@ -71,20 +71,20 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter {
 
     private buildGetInputFunctionValue(): Object {
         if (this.propertyPathFromSource.length === 1) {
-            return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0], this.toscaIndex]};
+            return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0], this.toscaIndexList]};
         }
-        return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource, this.toscaIndex]};
+        return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource, this.toscaIndexList]};
     }
 
     private buildFunctionValueWithPropertySource(): Object {
         if (this.propertySource == PropertySource.SELF) {
             return {
-                [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource, this.toscaIndex]
+                [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource, this.toscaIndexList]
             };
         }
         if (this.propertySource == PropertySource.INSTANCE) {
             return {
-                [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource,this.toscaIndex]
+                [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource,this.toscaIndexList]
             };
         }
     }
index c4a3893..24d622f 100644 (file)
@@ -44,7 +44,7 @@
     <!-- RIGHT CELL OR FULL WIDTH CELL-->
     <ng-container *ngIf="propType == derivedPropertyTypes.SIMPLE || property.isDeclared || (property.isToscaFunction() && !property.isChildOfListOrMap) || (property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP && property.schema.property.isSimpleType)">
         <div class="table-cell">
-            <checkbox class="{{propType == derivedPropertyTypes.MAP ? 'inline-checkBox' : 'inline-checkBox-List'}}" *ngIf="hideCheckBox === false && (property.isChildOfListOrMap && property.schema.property.isSimpleType)" [(checked)]="property.isSelected" [disabled]="property.isDisabled || readonly || property.mapKey == '' || checkboxDisabled" (checkedChange)="toggleTosca.emit(property)" ></checkbox>
+            <checkbox class="{{propType == derivedPropertyTypes.MAP ? 'inline-checkBox' : 'inline-checkBox-List'}}" *ngIf="hideCheckBox != true && (property.isChildOfListOrMap && property.schema.property.isSimpleType)" [(checked)]="property.isSelected" [disabled]="property.isDisabled || readonly || property.mapKey == '' || checkboxDisabled" (checkedChange)="toggleTosca.emit(property)" ></checkbox>
             <dynamic-element class="value-input"
                 pattern="validationUtils.getValidationPattern(property.type)"
                 [value]="(property.isDeclared || property.isToscaFunction()) ? property.value : property.valueObj"
index 4a9e110..a609db4 100644 (file)
       <select formControlName="selectedProperty" (change)="onPropertyValueChange()">
         <option *ngFor="let value of propertyDropdownList" [ngValue]="value">{{value.propertyLabel}}</option>
       </select>
-      <label class="i-sdc-form-label required" *ngIf="toscaIndexFlag">Index</label>
-      <input type="text" *ngIf="toscaIndexFlag" formControlName="toscaIndex" (change)="indexTokenChange()"/>
     </div>
     <div *ngIf="dropDownErrorMsg" class="tosca-error">{{dropDownErrorMsg}}</div>
   </form>
+  <div class="i-sdc-form-item" *ngFor="let indexVal of indexListValues; index as i">
+    <label class="i-sdc-form-label required" *ngIf="indexVal.indexFlag">Index</label>
+    <input type="text" *ngIf="indexVal.indexFlag" [(ngModel)]="indexVal.indexValue" (change)="indexTokenChange(indexVal)"/>
+    <label class="i-sdc-form-label required" *ngIf="indexVal.nestedFlag">{{dropdownValuesLabel}}</label>
+    <select [(ngModel)]="indexVal.indexProperty" *ngIf="indexVal.nestedFlag" (change)="onSubPropertyValueChange(indexVal,i)">
+      <option *ngFor="let value of indexVal.subPropertyArray" [ngValue]="value">{{value.propertyLabel}}</option>
+    </select>
+  </div>
   <loader [display]="isLoading" [size]="'medium'" [relative]="true"></loader>
 </div>
index 1b0a1a3..7987ba2 100644 (file)
@@ -53,8 +53,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     formGroup: FormGroup = new FormGroup({
         'selectedProperty': new FormControl(undefined, Validators.required),
-        'propertySource': new FormControl(undefined, Validators.required),
-        'toscaIndex' : new FormControl(undefined)
+        'propertySource': new FormControl(undefined, Validators.required)
     });
 
     isLoading: boolean = false;
@@ -63,7 +62,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
     dropdownValuesLabel: string;
     dropDownErrorMsg: string;
-    toscaIndexFlag: boolean = false;
+    indexListValues:Array<ToscaIndexObject>;
 
     private isInitialized: boolean = false;
     private componentMetadata: ComponentMetadata;
@@ -77,23 +76,9 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     ngOnInit(): void {
         this.componentMetadata = this.workspaceService.metadata;
+        this.indexListValues = [];
         this.formGroup.valueChanges.subscribe(() => {
-            if (!this.isInitialized) {
-                return;
-            }
-            let formGroupStatus : boolean = this.formGroup.valid;
-            const selectedProperty: PropertyDropdownValue = this.formGroup.value.selectedProperty;
-            if (selectedProperty != null && selectedProperty.isList && formGroupStatus 
-                && (this.toscaIndex.value == null || this.toscaIndex.value == '')) {
-                formGroupStatus = false;
-            }
-            this.onValidityChange.emit({
-                isValid: formGroupStatus,
-                toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
-            });
-            if (this.formGroup.valid) {
-                this.onValidFunction.emit(this.buildGetFunctionFromForm());
-            }
+            this.formValidation();
         });
         this.loadPropertySourceDropdown();
         this.loadPropertyDropdownLabel();
@@ -135,15 +120,36 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                 this.loadPropertyDropdown(() => {
                     this.selectedProperty
                     .setValue(this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName));
+                    if (this.toscaGetFunction.toscaIndexList.length > 0) {
+                        let tempSelectedProperty : PropertyDropdownValue = this.selectedProperty.value;
+                        this.toscaGetFunction.toscaIndexList.forEach((indexValue: string, index) => {
+                            let tempIndexFlag = false;
+                            let tempNestedFlag = false;
+                            let tempIndexValue = "0";
+                            let tempIndexProperty = tempSelectedProperty;
+                            let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
+                            if (index%2 == 0) {
+                                tempIndexFlag = true;
+                                tempIndexValue = indexValue;
+                                tempSelectedProperty = null;
+                                if (this.toscaGetFunction.toscaIndexList[index+1]) {
+                                    tempNestedFlag = true;
+                                    if (tempIndexProperty.schemaType != null) {
+                                        const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, tempIndexProperty.schemaType);
+                                        this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
+                                        tempSelectedProperty = subPropertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.toscaIndexList[index+1])
+                                    }
+                                }
+                                let tempIndexValueMap : ToscaIndexObject = {indexFlag : tempIndexFlag, nestedFlag : tempNestedFlag, indexValue: tempIndexValue, indexProperty: tempSelectedProperty, subPropertyArray: subPropertyDropdownList};
+                                this.indexListValues.push(tempIndexValueMap);
+                            }
+                        });
+                    }
                     subscriber.next();
                 });
             } else {
                 subscriber.next();
             }
-            if (this.toscaGetFunction.toscaIndex != null) {
-                this.toscaIndexFlag = true;
-                this.toscaIndex.setValue(this.toscaGetFunction.toscaIndex);
-            }
         });
     }
 
@@ -166,8 +172,16 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         toscaGetFunction.propertyUniqueId = selectedProperty.propertyId;
         toscaGetFunction.propertyName = selectedProperty.propertyName;
         toscaGetFunction.propertyPathFromSource = selectedProperty.propertyPath;
-        toscaGetFunction.toscaIndex = this.toscaIndex.value;
-
+        if (this.indexListValues.length > 0) {
+            let indexAndProperty : Array<string> = [];
+            this.indexListValues.forEach((indexObject : ToscaIndexObject) => {
+                indexAndProperty.push(indexObject.indexValue);
+                if(indexObject.nestedFlag && indexObject.indexProperty != null) {
+                    indexAndProperty.push(indexObject.indexProperty.propertyName);
+                }
+            });
+            toscaGetFunction.toscaIndexList = indexAndProperty;
+        }
         return toscaGetFunction;
     }
 
@@ -199,6 +213,33 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         });
     }
 
+    private formValidation(): void {
+        if (!this.isInitialized) {
+            return;
+        }
+        let formGroupStatus : boolean = this.formGroup.valid;
+        const selectedProperty: PropertyDropdownValue = this.formGroup.value.selectedProperty;
+        if (selectedProperty != null && selectedProperty.isList && formGroupStatus && this.indexListValues.length > 0) {
+            this.indexListValues.forEach((indexObject : ToscaIndexObject, index) => {
+                if (indexObject.indexValue == null) {
+                    formGroupStatus = false;
+                    return;
+                }
+                if (indexObject.nestedFlag && indexObject.indexProperty == null) {
+                    formGroupStatus = false;
+                    return;
+                }
+            });
+        }
+        this.onValidityChange.emit({
+            isValid: formGroupStatus,
+            toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
+        });
+        if (this.formGroup.valid) {
+            this.onValidFunction.emit(this.buildGetFunctionFromForm());
+        }
+    }
+
     private loadPropertyDropdown(onComplete?: () => any): void  {
         this.loadPropertyDropdownLabel();
         this.loadPropertyDropdownValues(onComplete);
@@ -232,7 +273,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     private resetPropertyDropdown(): void {
         this.dropDownErrorMsg = undefined;
         this.selectedProperty.reset();
-        this.toscaIndex.reset();
+        this.indexListValues = [];
         this.propertyDropdownList = [];
     }
 
@@ -246,7 +287,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
                 return;
             }
-            this.addPropertiesToDropdown(properties);
+            this.addPropertiesToDropdown(properties, this.propertyDropdownList);
             if (this.propertyDropdownList.length == 0) {
                 const msgCode = this.getNotFoundMsgCode();
                 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
@@ -359,12 +400,12 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         );
     }
 
-    private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue): void {
-        this.propertyDropdownList.push(propertyDropdownValue);
-        this.propertyDropdownList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
+    private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue, propertyList: Array<PropertyDropdownValue>): void {
+        propertyList.push(propertyDropdownValue);
+        propertyList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
     }
 
-    private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeBEModel>): void {
+    private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeBEModel>, propertyList: Array<PropertyDropdownValue>): void {
         for (const property of properties) {
             if (this.hasSameType(property)) {
                 this.addPropertyToDropdown({
@@ -372,15 +413,16 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                     propertyId: property.uniqueId,
                     propertyLabel: property.name,
                     propertyPath: [property.name],
-                    isList: property.type === PROPERTY_TYPES.LIST
-                });
+                    isList: property.type === PROPERTY_TYPES.LIST,
+                    schemaType: (property.type === PROPERTY_TYPES.LIST && this.isComplexType(property.schema.property.type)) ? property.schema.property.type : null
+                },propertyList);
             } else if (this.isComplexType(property.type)) {
-                this.fillPropertyDropdownWithMatchingChildProperties(property);
+                this.fillPropertyDropdownWithMatchingChildProperties(property,propertyList);
             }
         }
     }
 
-    private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeBEModel,
+    private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeBEModel, propertyList: Array<PropertyDropdownValue>,
                                                             parentPropertyList: Array<PropertyBEModel | AttributeBEModel> = []): void {
         const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
         if (!dataTypeFound || !dataTypeFound.properties) {
@@ -394,10 +436,11 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                     propertyId: parentPropertyList[0].uniqueId,
                     propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
                     propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name],
-                    isList : dataTypeProperty.type === PROPERTY_TYPES.LIST
-                });
+                    isList : dataTypeProperty.type === PROPERTY_TYPES.LIST,
+                    schemaType: (dataTypeProperty.type === PROPERTY_TYPES.LIST && this.isComplexType(dataTypeProperty.schema.property.type)) ? dataTypeProperty.schema.property.type : null
+                }, propertyList);
             } else if (this.isComplexType(dataTypeProperty.type)) {
-                this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, [...parentPropertyList])
+                this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, propertyList, [...parentPropertyList])
             }
         });
     }
@@ -409,8 +452,19 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         if (this.property.type === PROPERTY_TYPES.ANY) {
             return true;
         }
-        let validPropertyType = property.type;
-        let validPropertyTypeSchema = property.schemaType;
+        let validPropertyType = (this.property.type != PROPERTY_TYPES.LIST && property.type === PROPERTY_TYPES.LIST) ? property.schema.property.type : property.type;
+        if (this.property.type != PROPERTY_TYPES.LIST && property.type === PROPERTY_TYPES.LIST && this.isComplexType(validPropertyType)) {
+            let returnFlag : boolean = false;
+            const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, validPropertyType);
+            if (dataTypeFound && dataTypeFound.properties) {
+                dataTypeFound.properties.forEach(dataTypeProperty => {
+                    if (this.hasSameType(dataTypeProperty)) {
+                        returnFlag =  true;
+                    }
+                });
+            }
+            return returnFlag;
+        }
         if (this.typeHasSchema(this.property.type)) {
             if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty) || this.compositionMap) {
                 let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
@@ -421,13 +475,13 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
                     }
                     return validPropertyType === childObject.type;
                 }else{
-                    return validPropertyType === this.property.schemaType;
+                    return validPropertyType === this.property.schema.property.type;
                 }
             }
             if (!property.schema || !property.schema.property) {
                 return false;
             }
-            return validPropertyType === this.property.type && this.property.schemaType === validPropertyTypeSchema;
+            return validPropertyType === this.property.type && this.property.schema.property.type === property.schema.property.type;
         }
         if (this.property.schema.property.isDataType && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName){
             let typeToMatch = (<PropertyDeclareAPIModel> this.property).input.type;
@@ -438,7 +492,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
             return validPropertyType === typeToMatch;
         }
 
-        return validPropertyType === this.property.type || (validPropertyType === PROPERTY_TYPES.LIST && validPropertyTypeSchema === this.property.type);
+        return validPropertyType === this.property.type;
     }
 
     private getType(propertyPath:string[], type: string): string {
@@ -488,7 +542,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
 
     onPropertySourceChange(): void {
         this.selectedProperty.reset();
-        this.toscaIndex.reset();
+        this.indexListValues = [];
         if (!this.functionType || !this.propertySource.valid) {
             return;
         }
@@ -496,22 +550,66 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
     }
 
     onPropertyValueChange(): void {
-        this.toscaIndexFlag = false;
-        this.toscaIndex.reset();
+        let toscaIndexFlag = false;
+        let nestedToscaFlag = false;
+        this.indexListValues = [];
+        let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
         const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
-        if (selectedProperty.isList && this.property.type != PROPERTY_TYPES.LIST) {
-            this.toscaIndexFlag = true;
+        if (selectedProperty.isList) {
+            toscaIndexFlag = true;
+            if (selectedProperty.schemaType != null) {
+                nestedToscaFlag = true;
+                const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
+                this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
+            }
+        }
+        if (toscaIndexFlag || nestedToscaFlag) {
+            let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
+            this.indexListValues.push(indexValueMap);
+        }
+        this.formValidation();
+    }
+
+    onSubPropertyValueChange(indexObject : ToscaIndexObject, elementIndex: number): void {
+        let toscaIndexFlag = false;
+        let nestedToscaFlag = false;
+        let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
+        let selectedProperty: PropertyDropdownValue = indexObject.indexProperty;
+        if (selectedProperty.isList) {
+            toscaIndexFlag = true;
+            if (selectedProperty.schemaType != null) {
+                nestedToscaFlag = true;
+                const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
+                this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
+            }
         }
+        if (toscaIndexFlag || nestedToscaFlag) {
+            let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
+            if(!this.indexListValues[elementIndex+1]) {
+                this.indexListValues.push(indexValueMap);
+            } else {
+                this.indexListValues[elementIndex+1] = indexValueMap;
+            }
+        } else {
+            if(this.indexListValues[elementIndex+1]) {
+                this.indexListValues.splice((elementIndex+1),1);
+            }
+        }
+        this.formValidation();
     }
 
-    indexTokenChange(): void {
-        if ((this.toscaIndex.value).toLowerCase() === 'index') {
+    indexTokenChange(indexObject : ToscaIndexObject): void {
+        if ((indexObject.indexValue).toLowerCase() === 'index') {
+            this.formValidation();
             return;
         }
-        let indexTokenValue = Number(this.toscaIndex.value);
+        let indexTokenValue = Number(indexObject.indexValue);
         if (isNaN(indexTokenValue)) {
-            this.toscaIndex.reset();
+            indexObject.indexValue = "0";
+            this.formValidation();
+            return;
         }
+        this.formValidation();
     }
 
     showPropertySourceDropdown(): boolean {
@@ -530,10 +628,6 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges {
         return this.formGroup.get('selectedProperty') as FormControl;
     }
 
-    private get toscaIndex(): FormControl {
-        return this.formGroup.get('toscaIndex') as FormControl;
-    }
-
 }
 
 export interface PropertyDropdownValue {
@@ -542,6 +636,15 @@ export interface PropertyDropdownValue {
     propertyLabel: string;
     propertyPath: Array<string>;
     isList: boolean;
+    schemaType: string;
+}
+
+export interface ToscaIndexObject {
+    indexFlag: boolean;
+    nestedFlag: boolean;
+    indexValue: string;
+    indexProperty: PropertyDropdownValue;
+    subPropertyArray: Array<PropertyDropdownValue>;
 }
 
 export interface ToscaGetFunctionValidationEvent {
index de8e30b..f77c6f9 100644 (file)
@@ -116,7 +116,8 @@ public class ToscaFunctionJsonDeserializer extends StdDeserializer<ToscaFunction
         toscaGetFunction.setSourceUniqueId(getAsTextOrElseNull(node, "sourceUniqueId"));
         toscaGetFunction.setPropertyName(getAsTextOrElseNull(node, "propertyName"));
         toscaGetFunction.setPropertyUniqueId(getAsTextOrElseNull(node, "propertyUniqueId"));
-        toscaGetFunction.setToscaIndex(getNumberAsTextOrElseNull(node, "toscaIndex"));
+        toscaGetFunction.setToscaIndexList(getNumberAsTextOrElseNull(node, "toscaIndexList", context));
+
         final String propertySource = getAsTextOrElseNull(node, "propertySource");
         if (StringUtils.isNotEmpty(propertySource)) {
             final PropertySource propertySource1 = PropertySource.findType(propertySource).orElseThrow(() ->
@@ -149,20 +150,31 @@ public class ToscaFunctionJsonDeserializer extends StdDeserializer<ToscaFunction
         return jsonNode.asText();
     }
 
-    private Object getNumberAsTextOrElseNull(final JsonNode node, final String fieldName) {
+    private List<Object> getNumberAsTextOrElseNull(final JsonNode node, final String fieldName, final DeserializationContext context) throws JsonMappingException{
+        List<Object> toscaIndexList = new ArrayList<Object>();
         final JsonNode jsonNode = node.get(fieldName);
-        if (jsonNode == null) {
-            return null;
-        }
-        if (jsonNode.asText().equalsIgnoreCase("INDEX")) {
-            return jsonNode.asText();
-        }
-        try {
-            Integer.parseInt(jsonNode.asText());
-        } catch(Exception e) {
-            return null;
+        if (jsonNode != null) {
+            if (!jsonNode.isArray()) {
+                throw context.instantiationException(ToscaGetFunctionDataDefinition.class, "Expecting an array for toscaIndexList attribute");
+            }
+            for (int index=0;index<jsonNode.size();index++) {
+                String textValue = jsonNode.get(index).asText();
+                if (index%2 == 0) {
+                    if (textValue.equalsIgnoreCase("INDEX")) {
+                        toscaIndexList.add(textValue);
+                    } else {
+                        try {
+                            toscaIndexList.add(Integer.parseInt(textValue));
+                        } catch(Exception e) {
+                            throw context.instantiationException(ToscaGetFunctionDataDefinition.class, "Expecting a valid value for toscaIndex attribute");
+                        }
+                    }
+                } else {
+                    toscaIndexList.add(textValue);
+                }
+            }
         }
-        return Integer.parseInt(jsonNode.asText());
+        return toscaIndexList;
     }
 
     private ToscaConcatFunction deserializeConcatFunction(final JsonNode concatFunctionJsonNode,
index 9396188..5bd9fe3 100644 (file)
@@ -44,7 +44,7 @@ public class ToscaGetFunctionDataDefinition implements ToscaFunction, ToscaFunct
     private String sourceName;
     private ToscaGetFunctionType functionType;
     private List<String> propertyPathFromSource = new ArrayList<>();
-    private Object toscaIndex;
+    private List<Object> toscaIndexList;
 
     public ToscaGetFunctionDataDefinition() {
         //necessary for JSON conversions
@@ -89,10 +89,13 @@ public class ToscaGetFunctionDataDefinition implements ToscaFunction, ToscaFunct
             );
         }
         if (propertySource == PropertySource.SELF) {
-            if (toscaIndex != null) {
-                Object toscaIndexValue = StringUtils.isNumeric(toscaIndex.toString()) ? Integer.parseInt(toscaIndex.toString()) : toscaIndex;
+            if (toscaIndexList.size() > 0) {
+                List<Object> parsedIndexList = new ArrayList<Object>();
+                toscaIndexList.forEach((obj) -> {
+                    parsedIndexList.add(StringUtils.isNumeric(obj.toString()) ? Integer.parseInt(obj.toString()) : obj);
+                });
                 return Map.of(functionType.getFunctionName(),
-                    Stream.concat(Stream.of(PropertySource.SELF.getName()), Stream.concat(propertyPathFromSource.stream(),Stream.of(toscaIndexValue))).collect(Collectors.toList())
+                    Stream.concat(Stream.of(PropertySource.SELF.getName()), Stream.concat(propertyPathFromSource.stream(),parsedIndexList.stream())).collect(Collectors.toList())
                 );
             }
             return Map.of(functionType.getFunctionName(),
@@ -105,10 +108,13 @@ public class ToscaGetFunctionDataDefinition implements ToscaFunction, ToscaFunct
                     String.format("sourceName is required in order to generate the %s from INSTANCE value", functionType.getFunctionName())
                 );
             }
-            if (toscaIndex != null) {
-                Object toscaIndexValue = StringUtils.isNumeric(toscaIndex.toString()) ? Integer.parseInt(toscaIndex.toString()) : toscaIndex;
+            if (toscaIndexList.size() > 0) {
+                List<Object> parsedIndexList = new ArrayList<Object>();
+                toscaIndexList.forEach((obj) -> {
+                    parsedIndexList.add(StringUtils.isNumeric(obj.toString()) ? Integer.parseInt(obj.toString()) : obj);
+                });
                 return Map.of(functionType.getFunctionName(),
-                    Stream.concat(Stream.of(sourceName), Stream.concat(propertyPathFromSource.stream(),Stream.of(toscaIndexValue))).collect(Collectors.toList())
+                    Stream.concat(Stream.of(sourceName), Stream.concat(propertyPathFromSource.stream(),parsedIndexList.stream())).collect(Collectors.toList())
                 );
             }
             return Map.of(functionType.getFunctionName(),
@@ -123,10 +129,9 @@ public class ToscaGetFunctionDataDefinition implements ToscaFunction, ToscaFunct
         List<Object> propertySourceCopy = new ArrayList<Object>(this.propertyPathFromSource);
         List<Object> propertySourceOneCopy = new ArrayList<>();
         propertySourceOneCopy.add(this.propertyPathFromSource.get(0));
-        if (toscaIndex != null) {
-            Object toscaIndexValue = StringUtils.isNumeric(toscaIndex.toString()) ? Integer.parseInt(toscaIndex.toString()) : toscaIndex;
-            propertySourceCopy.add(toscaIndexValue);
-            propertySourceOneCopy.add(toscaIndexValue);
+        if (toscaIndexList.size() > 0) {
+            propertySourceCopy.addAll(toscaIndexList);
+            propertySourceOneCopy.addAll(toscaIndexList);
         }
         if (this.propertyPathFromSource.size() == 1) {
             return Map.of(this.functionType.getFunctionName(), propertySourceOneCopy);
index 581f62a..3add149 100644 (file)
@@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import com.google.gson.Gson;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -206,6 +207,7 @@ class ToscaGetFunctionDataDefinitionTest {
         toscaGetFunction.setPropertySource(propertySource);
         toscaGetFunction.setPropertyPathFromSource(propertyPath);
         toscaGetFunction.setSourceName(sourceName);
+        toscaGetFunction.setToscaIndexList(new ArrayList<>());
         return toscaGetFunction;
     }