Support of get_property for instance properties 12/129412/8
authorandre.schmid <andre.schmid@est.tech>
Fri, 27 May 2022 10:58:10 +0000 (11:58 +0100)
committerMichael Morris <michael.morris@est.tech>
Thu, 2 Jun 2022 13:38:18 +0000 (13:38 +0000)
Support of get_property for INSTANCE properties, as currently only
SELF properties can be selected.

Change-Id: I80611002964a6ebb515134155c321f2d7f87811c
Issue-ID: SDC-4026
Signed-off-by: andre.schmid <andre.schmid@est.tech>
14 files changed:
catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ToscaGetFunctionExceptionSupplier.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-ui/src/app/models/tosca-get-function.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts
catalog-ui/src/app/ng2/components/logic/policies-table/policies-table.component.ts
catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/services/properties.utils.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts
catalog-ui/src/assets/languages/en_US.json

index 99abb7b..53f7c1d 100644 (file)
@@ -2717,3 +2717,11 @@ errors:
         messageId: "SVC4170"
     }
 
+    #---------SVC4171-----------------------------
+    # %1 - Instance name
+    TOSCA_GET_FUNCTION_INSTANCE_NOT_FOUND: {
+        code: 404,
+        message: "The instance '%1' was not found.",
+        messageId: "SVC4171"
+    }
+
index 1fa459d..7ea00b1 100644 (file)
@@ -2374,12 +2374,21 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
 
     private <T extends PropertyDefinition> void validateToscaGetFunction(T property, Component parentComponent) {
         final ToscaGetFunctionDataDefinition toscaGetFunction = property.getToscaGetFunction();
+        validateGetPropertySource(toscaGetFunction.getFunctionType(), toscaGetFunction.getPropertySource());
         if (toscaGetFunction.getFunctionType() == ToscaGetFunctionType.GET_INPUT) {
             validateGetFunction(property, parentComponent.getInputs(), parentComponent.getModel());
             return;
         }
         if (toscaGetFunction.getFunctionType() == ToscaGetFunctionType.GET_PROPERTY) {
-            validateGetFunction(property, parentComponent.getProperties(), parentComponent.getModel());
+            if (toscaGetFunction.getPropertySource() == PropertySource.SELF) {
+                validateGetFunction(property, parentComponent.getProperties(), parentComponent.getModel());
+            } else if (toscaGetFunction.getPropertySource() == PropertySource.INSTANCE) {
+                final ComponentInstance componentInstance =
+                    parentComponent.getComponentInstanceById(toscaGetFunction.getSourceUniqueId())
+                        .orElseThrow(ToscaGetFunctionExceptionSupplier.instanceNotFound(toscaGetFunction.getSourceName()));
+                validateGetFunction(property, componentInstance.getProperties(), parentComponent.getModel());
+            }
+
             return;
         }
 
@@ -2396,7 +2405,6 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                     toscaGetFunction.getFunctionType()
                 ).get();
         }
-        validateGetPropertySource(toscaGetFunction.getFunctionType(), toscaGetFunction.getPropertySource());
         final String getFunctionPropertyUniqueId = toscaGetFunction.getPropertyUniqueId();
         T referredProperty = (T) parentProperties.stream()
             .filter(property1 -> getFunctionPropertyUniqueId.equals(property1.getUniqueId()))
@@ -2458,7 +2466,11 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     private void validateGetPropertySource(final ToscaGetFunctionType functionType, final PropertySource propertySource) {
-        if (propertySource != PropertySource.SELF) {
+        if (functionType == ToscaGetFunctionType.GET_INPUT && propertySource != PropertySource.SELF) {
+            throw ToscaGetFunctionExceptionSupplier
+                .targetSourceNotSupported(functionType, propertySource).get();
+        }
+        if (functionType == ToscaGetFunctionType.GET_PROPERTY && !List.of(PropertySource.SELF, PropertySource.INSTANCE).contains(propertySource)) {
             throw ToscaGetFunctionExceptionSupplier
                 .targetSourceNotSupported(functionType, propertySource).get();
         }
index d54cb79..5e1d005 100644 (file)
@@ -91,4 +91,12 @@ public class ToscaGetFunctionExceptionSupplier {
             functionType.getFunctionName(), referredPropertySchemaType, propertySchemaType
         );
     }
+
+    public static Supplier<ByActionStatusComponentException> instanceNotFound(final String instanceName) {
+        return () -> new ByActionStatusComponentException(
+            ActionStatus.TOSCA_GET_FUNCTION_INSTANCE_NOT_FOUND,
+            instanceName
+        );
+    }
+
 }
index c0ad54c..c7d66bf 100644 (file)
@@ -396,7 +396,7 @@ class ComponentInstanceBusinessLogicTest {
             getPropertyPropertyName,
             mapToscaType,
             "string",
-            String.format("get_property: [\"%s\"]", String.join(",", containerPropertyPath)),
+            String.format("\"get_property\": [\"%s\", \"%s\"]", PropertySource.SELF, String.join("\", \"", containerPropertyPath)),
             createGetToscaFunction(containerPropertyPath.get(containerPropertyPath.size() - 1), containerPropertyId,
                 containerPropertyPath, PropertySource.SELF, ToscaGetFunctionType.GET_PROPERTY, containerComponentId, containerComponentName)
         );
@@ -458,6 +458,60 @@ class ComponentInstanceBusinessLogicTest {
         assertThat(actualResponseFormat.left().value()).isEqualTo(resourceInstanceProperties);
     }
 
+    @Test
+    void testToscaGetPropertyOnInstanceValidation() {
+        final String userId = "userId";
+        final String containerComponentId = "containerComponentId";
+        final String containerComponentName = "containerComponentName";
+        final String instanceUniqueId = String.format("%s.%s", containerComponentId, "instanceId");
+
+        final List<String> parentPropertyPath = List.of("property1");
+        final String containerPropertyId = String.format("%s.%s", containerComponentId, parentPropertyPath.get(0));
+        final ComponentInstanceProperty getPropertyOnInstanceProperty = createComponentInstanceProperty(
+            String.format("%s.%s", containerComponentId, "getPropertyOnInstanceProperty"),
+            "getPropertyOnInstanceProperty",
+            "string",
+            null,
+            String.format("\"get_property\": [\"%s\", \"%s\"]", PropertySource.INSTANCE, parentPropertyPath.get(0)),
+            createGetToscaFunction(parentPropertyPath.get(0), containerPropertyId, parentPropertyPath, PropertySource.INSTANCE,
+                ToscaGetFunctionType.GET_PROPERTY, instanceUniqueId, containerComponentName)
+        );
+
+        //creating component that has the instance properties
+        final Component component = new Service();
+        component.setUniqueId(containerComponentId);
+        component.setName(containerComponentName);
+        component.setLastUpdaterUserId(userId);
+        component.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT);
+        //adding instance properties to the component
+        final List<ComponentInstanceProperty> resourceInstanceProperties = List.of(getPropertyOnInstanceProperty);
+        final Map<String, List<ComponentInstanceProperty>> componentInstanceProps = new HashMap<>();
+        componentInstanceProps.put(instanceUniqueId, resourceInstanceProperties);
+        component.setComponentInstancesProperties(componentInstanceProps);
+
+        //creating resource property that will be get
+        final var propertyDefinition = new PropertyDefinition();
+        propertyDefinition.setName(parentPropertyPath.get(0));
+        propertyDefinition.setUniqueId(containerPropertyId);
+        final String property1Type = "string";
+        propertyDefinition.setType(property1Type);
+        //creating resource instance to be added to the component
+        final ComponentInstance resourceInstance = createComponentInstance("resourceInstance");
+        resourceInstance.setUniqueId(instanceUniqueId);
+        resourceInstance.setProperties(List.of(propertyDefinition));
+        component.setComponentInstances(List.of(resourceInstance));
+
+        mockComponentForToscaGetFunctionValidation(component);
+
+        //when
+        final Either<List<ComponentInstanceProperty>, ResponseFormat> actualResponseFormat = componentInstanceBusinessLogic
+            .createOrUpdatePropertiesValues(
+                ComponentTypeEnum.RESOURCE_INSTANCE, containerComponentId, instanceUniqueId, resourceInstanceProperties, userId);
+        //then
+        assertTrue(actualResponseFormat.isLeft());
+        assertThat(actualResponseFormat.left().value()).isEqualTo(resourceInstanceProperties);
+    }
+
     private DataTypeDefinition createDataType(final String name, final Map<String, String> propertyNameAndTypeMap) {
         final var dataTypeDefinition = new DataTypeDefinition();
         dataTypeDefinition.setName(name);
index 6b911e0..9bf149f 100644 (file)
@@ -137,5 +137,6 @@ public enum ActionStatus {
     TOSCA_GET_FUNCTION_TYPE_DIVERGE,
     TOSCA_GET_FUNCTION_SCHEMA_DIVERGE,
     TOSCA_GET_FUNCTION_PROPERTY_DATA_TYPE_NOT_FOUND,
-    TOSCA_GET_FUNCTION_PROPERTY_NOT_FOUND
+    TOSCA_GET_FUNCTION_PROPERTY_NOT_FOUND,
+    TOSCA_GET_FUNCTION_INSTANCE_NOT_FOUND
 }
diff --git a/catalog-ui/src/app/models/tosca-get-function.ts b/catalog-ui/src/app/models/tosca-get-function.ts
new file mode 100644 (file)
index 0000000..0fe0831
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2022 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+import {PropertySource} from "./property-source";
+import {ToscaGetFunctionType} from "./tosca-get-function-type";
+
+export class ToscaGetFunction {
+    propertyUniqueId: string;
+    propertyName: string;
+    propertySource: PropertySource;
+    sourceUniqueId: string;
+    sourceName: string;
+    functionType: ToscaGetFunctionType;
+    propertyPathFromSource: Array<string>;
+}
\ No newline at end of file
index 5ca119c..822d8c9 100644 (file)
@@ -39,7 +39,7 @@ import { DynamicElementComponent } from "../../ui/dynamic-element/dynamic-elemen
 export class InputsTableComponent {
 
     @Input() inputs: Array<InputFEModel>;
-    @Input() instanceNamesMap: Map<string, InstanceFeDetails>;
+    @Input() instanceNamesMap: { [key: string]: InstanceFeDetails };
     @Input() readonly: boolean;
     @Input() isLoading: boolean;
     @Input() componentType: string;
index 9613439..9286dc6 100644 (file)
@@ -28,7 +28,7 @@ import { ModalService } from '../../../services/modal.service';
 export class PoliciesTableComponent {
 
     @Input() policies: PolicyInstance[];
-    @Input() instanceNamesMap: Map<string, InstanceFeDetails>;
+    @Input() instanceNamesMap: { [key: string]: InstanceFeDetails };
     @Input() readonly: boolean;
     @Input() isLoading: boolean;
     @Output() deletePolicy: EventEmitter<any> = new EventEmitter<any>();
index b79bec0..f787286 100644 (file)
@@ -33,7 +33,7 @@ import { ModalService } from '../../../services/modal.service';
 export class PropertiesTableComponent implements OnChanges {
 
     @Input() fePropertiesMap: InstanceFePropertiesMap;
-    @Input() feInstanceNamesMap: Map<string, InstanceFeDetails>;
+    @Input() feInstanceNamesMap: { [key: string]: InstanceFeDetails };
     @Input() selectedPropertyId: string;
     @Input() propertyNameSearchText: string;
     @Input() searchTerm: string;
index 2d491cd..6584b47 100644 (file)
@@ -61,15 +61,13 @@ import {UnsavedChangesComponent} from "app/ng2/components/ui/forms/unsaved-chang
 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
 import {ModalService} from "../../services/modal.service";
 import {DeclareListComponent} from "./declare-list/declare-list.component";
-import {PropertyDropdownValue, ToscaFunctionComponent} from "./tosca-function/tosca-function.component";
+import {ToscaFunctionComponent} from "./tosca-function/tosca-function.component";
 import {CapabilitiesGroup, Capability} from "../../../models/capability";
 import {ToscaPresentationData} from "../../../models/tosca-presentation";
 import {Observable} from "rxjs";
-import {ToscaGetFunctionType} from "../../../models/tosca-get-function-type";
 import {TranslateService} from "../../shared/translator/translate.service";
 import {ToscaGetFunctionDtoBuilder} from '../../../models/tosca-get-function-dto';
-import {PropertySource} from '../../../models/property-source';
-import {ToscaGetFunctionTypeConverter} from '../../../models/tosca-get-function-type-converter';
+import {ToscaGetFunction} from "../../../models/tosca-get-function";
 
 const SERVICE_SELF_TITLE = "SELF";
 @Component({
@@ -80,7 +78,8 @@ export class PropertiesAssignmentComponent {
     title = "Properties & Inputs";
 
     component: ComponentData;
-    componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
+    componentInstanceNamesMap: { [key: string]: InstanceFeDetails } = {}; //key is the instance uniqueId
+    componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>(); //key is the instance uniqueId
 
     propertiesNavigationData = [];
     instancesNavigationData = [];
@@ -183,6 +182,16 @@ export class PropertiesAssignmentComponent {
             this.instances.push(...response.groupInstances);
             this.instances.push(...response.policies);
 
+            if (response.componentInstances) {
+                response.componentInstances.forEach(instance => {
+                    this.componentInstanceMap.set(instance.uniqueId, <InstanceFeDetails>{
+                        name: instance.name,
+                        iconClass: instance.iconClass,
+                        originArchived: instance.originArchived
+                    });
+                });
+            }
+
             _.forEach(response.policies, (policy: any) => {
                 const newPolicy: InputFEModel = new InputFEModel(policy);
                 this.inputsUtils.resetInputDefaultValue(newPolicy, policy.defaultValue);
@@ -542,10 +551,8 @@ export class PropertiesAssignmentComponent {
             [
                 new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
                     () => {
-                        const selectedToscaFunction = modal.instance.dynamicContent.instance.selectToscaFunction;
-                        const selectedPropertyFromModal:PropertyDropdownValue = modal.instance.dynamicContent.instance.selectedProperty;
-                        const toscaFunctionType: ToscaGetFunctionType = ToscaGetFunctionTypeConverter.convertFromString(selectedToscaFunction);
-                        this.updateCheckedInstancePropertyGetFunctionValue(selectedPropertyFromModal, toscaFunctionType);
+                        const toscaGetFunction: ToscaGetFunction = modal.instance.dynamicContent.instance.toscaGetFunction;
+                        this.updateCheckedInstancePropertyGetFunctionValue(toscaGetFunction);
                         modal.instance.close();
                     }
                 ),
@@ -558,6 +565,7 @@ export class PropertiesAssignmentComponent {
         const checkedInstanceProperty = this.buildCheckedInstanceProperty();
         this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
             'property': checkedInstanceProperty,
+            'componentInstanceMap': this.componentInstanceMap
         });
         modal.instance.open();
     }
@@ -570,20 +578,18 @@ export class PropertiesAssignmentComponent {
         this.updateInstanceProperty(checkedInstanceProperty);
     }
 
-    private updateCheckedInstancePropertyGetFunctionValue(propertyToGet: PropertyDropdownValue, toscaGetFunctionType: ToscaGetFunctionType) {
+    private updateCheckedInstancePropertyGetFunctionValue(toscaGetFunction: ToscaGetFunction) {
         const toscaGetFunctionBuilder: ToscaGetFunctionDtoBuilder =
             new ToscaGetFunctionDtoBuilder()
-                .withPropertyUniqueId(propertyToGet.propertyId)
-                .withFunctionType(toscaGetFunctionType)
-                .withPropertySource(PropertySource.SELF)
-                .withPropertyName(propertyToGet.propertyName)
-                .withSourceName(this.component.name)
-                .withSourceUniqueId(this.component.uniqueId);
+                .withPropertyUniqueId(toscaGetFunction.propertyUniqueId)
+                .withFunctionType(toscaGetFunction.functionType)
+                .withPropertySource(toscaGetFunction.propertySource)
+                .withPropertyName(toscaGetFunction.propertyName)
+                .withSourceName(toscaGetFunction.sourceName)
+                .withSourceUniqueId(toscaGetFunction.sourceUniqueId)
+                .withPropertyPathFromSource(toscaGetFunction.propertyPathFromSource);
 
         const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
-        if (propertyToGet.propertyPath && propertyToGet.propertyPath.length) {
-            toscaGetFunctionBuilder.withPropertyPathFromSource(propertyToGet.propertyPath);
-        }
         checkedProperty.toscaGetFunction = toscaGetFunctionBuilder.build();
         this.updateInstanceProperty(checkedProperty);
     }
index 02dbf91..70c9303 100644 (file)
@@ -47,7 +47,9 @@ export class PropertiesUtils {
                 if (this.dataTypeService.getDataTypeByModelAndTypeName(model, property.type)) { // if type not exist in data types remove property from list
 
                     let newFEProp: PropertyFEModel = new PropertyFEModel(property); //Convert property to FE
-
+                    if (!newFEProp.parentUniqueId) {
+                        newFEProp.parentUniqueId = instanceId;
+                    }
                     this.initValueObjectRef(newFEProp); //initialize valueObj AND creates flattened children
                     propertyFeArray.push(newFEProp);
                     newFEProp.updateExpandedChildPropertyId(newFEProp.name); //display only the first level of children
index 851d7b6..1f81ebe 100644 (file)
   <loader [display]="isLoading" [loaderDelay]="500" [relative]="true" [size]="'large'"></loader>
   <form class="w-sdc-form">
     <div class="i-sdc-form-item">
-      <label class="i-sdc-form-label required">TOSCA function</label>
-      <select [(ngModel)]="selectToscaFunction" (change)="onToscaFunctionChange()" name="selectToscaFunction">
+      <label class="i-sdc-form-label required">{{'TOSCA_FUNCTION_LABEL' | translate}}</label>
+      <select [(ngModel)]="toscaGetFunction.functionType" (change)="onToscaFunctionChange()" name="toscaFunctionType">
         <option *ngFor="let toscaFunction of toscaFunctions"
-                [ngValue]="toscaFunction">{{toscaFunction}}</option>
+                [ngValue]="toscaFunction">{{toscaFunction | lowercase}}</option>
+      </select>
+    </div>
+    <div class="i-sdc-form-item" *ngIf="toscaGetFunction.functionType === TOSCA_FUNCTION_GET_PROPERTY">
+      <label class="i-sdc-form-label required">{{'TOSCA_FUNCTION_PROPERTY_SOURCE_LABEL' | translate}}</label>
+      <select name="propertySource" [(ngModel)]="propertySource" (change)="onPropertySourceChange()">
+        <option *ngFor="let propertySource of propertySourceList"
+                [ngValue]="propertySource">{{propertySource}}</option>
       </select>
     </div>
     <div *ngIf="showDropdown()" class="i-sdc-form-item">
       <label class="i-sdc-form-label required">{{dropdownValuesLabel}}</label>
-      <select [(ngModel)]="selectedProperty" name="selectedProperty">
+      <select [(ngModel)]="selectedProperty" name="selectedProperty" (change)="onPropertyChange()">
         <option *ngFor="let value of propertyDropdownList" [ngValue]="value">{{value.propertyLabel}}</option>
       </select>
     </div>
index 6e013d7..054a21f 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 import {Component, Input} from '@angular/core';
-import {ComponentMetadata, DataTypeModel, PropertyBEModel} from 'app/models';
+import {ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel} from 'app/models';
 import {TopologyTemplateService} from "../../../services/component-services/topology-template.service";
 import {WorkspaceService} from "../../workspace/workspace.service";
 import {PropertiesService} from "../../../services/properties.service";
@@ -28,6 +28,9 @@ import {ToscaGetFunctionType} from "../../../../models/tosca-get-function-type";
 import {TranslateService} from "../../../shared/translator/translate.service";
 import {ComponentGenericResponse} from '../../../services/responses/component-generic-response';
 import {Observable} from 'rxjs/Observable';
+import {PropertySource} from "../../../../models/property-source";
+import {InstanceFeDetails} from "../../../../models/instance-fe-details";
+import {ToscaGetFunction} from "../../../../models/tosca-get-function";
 
 @Component({
     selector: 'tosca-function',
@@ -37,14 +40,20 @@ import {Observable} from 'rxjs/Observable';
 export class ToscaFunctionComponent {
 
     @Input() property: PropertyBEModel;
+    @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+
+    TOSCA_FUNCTION_GET_PROPERTY = ToscaGetFunctionType.GET_PROPERTY;
 
-    selectToscaFunction;
     selectedProperty: PropertyDropdownValue;
     isLoading: boolean = false;
     propertyDropdownList: Array<PropertyDropdownValue> = [];
     toscaFunctions: Array<string> = [];
+    propertySourceList: Array<string> = [];
+    instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
     dropdownValuesLabel: string;
     dropDownErrorMsg: string;
+    propertySource: string
+    toscaGetFunction: ToscaGetFunction = new ToscaGetFunction();
 
     private componentMetadata: ComponentMetadata;
 
@@ -58,20 +67,55 @@ export class ToscaFunctionComponent {
     ngOnInit() {
         this.componentMetadata = this.workspaceService.metadata;
         this.loadToscaFunctions();
+        this.loadPropertySourceDropdown();
     }
 
     private loadToscaFunctions(): void {
-        this.toscaFunctions.push(ToscaGetFunctionType.GET_INPUT.toLowerCase());
-        this.toscaFunctions.push(ToscaGetFunctionType.GET_PROPERTY.toLowerCase());
+        this.toscaFunctions.push(ToscaGetFunctionType.GET_INPUT);
+        this.toscaFunctions.push(ToscaGetFunctionType.GET_PROPERTY);
+    }
+
+    private loadPropertySourceDropdown() {
+        this.propertySourceList.push(PropertySource.SELF);
+        this.componentInstanceMap.forEach((value, key) => {
+            const instanceName = value.name;
+            this.instanceNameAndIdMap.set(instanceName, key);
+            if (instanceName !== PropertySource.SELF) {
+                this.addToPropertySource(instanceName);
+            }
+        });
+    }
+
+    private addToPropertySource(source: string) {
+        this.propertySourceList.push(source);
+        this.propertySourceList.sort((a, b) => {
+            if (a === PropertySource.SELF) {
+                return -1;
+            } else if (b === PropertySource.SELF) {
+                return 1;
+            }
+
+            return a.localeCompare(b);
+        });
     }
 
     onToscaFunctionChange(): void {
-        this.loadDropdownValueLabel();
-        this.loadDropdownValues();
+        this.toscaGetFunction.propertyUniqueId = undefined;
+        this.toscaGetFunction.propertyName = undefined;
+        this.toscaGetFunction.propertySource = undefined;
+        this.toscaGetFunction.sourceUniqueId = undefined;
+        this.toscaGetFunction.sourceName = undefined;
+        this.toscaGetFunction.propertyPathFromSource = undefined;
+        this.propertySource = undefined;
+        if (this.isGetInputSelected()) {
+            this.setSelfPropertySource();
+            this.loadDropdownValueLabel();
+            this.loadDropdownValues();
+        }
     }
 
     private loadDropdownValueLabel(): void {
-        if (!this.selectToscaFunction) {
+        if (!this.toscaGetFunction.functionType) {
             return;
         }
         if (this.isGetInputSelected()) {
@@ -82,7 +126,7 @@ export class ToscaFunctionComponent {
     }
 
     private loadDropdownValues(): void {
-        if (!this.selectToscaFunction) {
+        if (!this.toscaGetFunction.functionType) {
             return;
         }
         this.resetDropDown();
@@ -96,30 +140,59 @@ export class ToscaFunctionComponent {
 
     private loadPropertiesInDropdown() {
         this.startLoading();
-        let propertiesObservable: Observable<ComponentGenericResponse>
+        const propertiesObservable: Observable<ComponentGenericResponse> = this.getPropertyObservable();
+        propertiesObservable.subscribe( (response: ComponentGenericResponse) => {
+            const properties: PropertyBEModel[] = this.extractProperties(response);
+            if (!properties || properties.length === 0) {
+                const msgCode = this.isGetInputSelected() ? 'TOSCA_FUNCTION_NO_INPUT_FOUND' : 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.property.type});
+                return;
+            }
+            this.addPropertiesToDropdown(properties);
+            if (this.propertyDropdownList.length == 0) {
+                const msgCode = this.isGetInputSelected() ? 'TOSCA_FUNCTION_NO_INPUT_FOUND' : 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.property.type});
+            }
+        }, (error) => {
+            console.error('An error occurred while loading properties.', error);
+        }, () => {
+            this.stopLoading();
+        });
+    }
+
+    private extractProperties(componentGenericResponse: ComponentGenericResponse): PropertyBEModel[] {
         if (this.isGetInputSelected()) {
-            propertiesObservable = this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
-        } else if (this.isGetPropertySelected()) {
-            propertiesObservable = this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+            return componentGenericResponse.inputs;
+        }
+        if (this.isGetPropertySelected()) {
+            if (this.propertySource === PropertySource.SELF) {
+                return componentGenericResponse.properties;
+            }
+            const componentInstanceProperties: PropertyModel[] = componentGenericResponse.componentInstancesProperties[this.instanceNameAndIdMap.get(this.propertySource)];
+            return this.removeSelectedProperty(componentInstanceProperties);
+        }
+    }
+
+    private getPropertyObservable(): Observable<ComponentGenericResponse> {
+        if (this.isGetInputSelected()) {
+            return this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+        }
+        if (this.isGetPropertySelected()) {
+            if (this.propertySource === PropertySource.SELF) {
+                return this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+            }
+            return this.topologyTemplateService.getComponentInstanceProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
         }
-        propertiesObservable
-            .subscribe( (response: ComponentGenericResponse) => {
-                let properties: PropertyBEModel[] = this.isGetInputSelected() ? response.inputs : response.properties;
-                if (!properties || properties.length === 0) {
-                    const msgCode = this.isGetInputSelected() ? 'TOSCA_FUNCTION_NO_INPUT_FOUND' : 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
-                    this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.property.type});
-                    return;
-                }
-                this.addPropertiesToDropdown(properties);
-                if (this.propertyDropdownList.length == 0) {
-                    const msgCode = this.isGetInputSelected() ? 'TOSCA_FUNCTION_NO_INPUT_FOUND' : 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
-                    this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.property.type});
-                }
-            }, (error) => {
-                console.error('An error occurred while loading properties.', error);
-            }, () => {
-                this.stopLoading();
-            });
+    }
+
+    private removeSelectedProperty(componentInstanceProperties: PropertyModel[]): PropertyModel[] {
+        if (!componentInstanceProperties) {
+            return [];
+        }
+        return componentInstanceProperties.filter(property =>
+            (property.uniqueId !== this.property.uniqueId) ||
+            (property.uniqueId === this.property.uniqueId && property.resourceInstanceUniqueId !== this.property.parentUniqueId)
+        );
     }
 
     private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue) {
@@ -134,7 +207,6 @@ export class ToscaFunctionComponent {
                     propertyName: property.name,
                     propertyId: property.uniqueId,
                     propertyLabel: property.name,
-                    toscaFunction: this.selectToscaFunction,
                     propertyPath: [property.name]
                 });
             } else if (this.isComplexType(property.type)) {
@@ -155,7 +227,6 @@ export class ToscaFunctionComponent {
                     propertyName: dataTypeProperty.name,
                     propertyId: parentPropertyList[0].uniqueId,
                     propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
-                    toscaFunction: this.selectToscaFunction,
                     propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name]
                 });
             } else if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(dataTypeProperty.type) === -1) {
@@ -165,11 +236,11 @@ export class ToscaFunctionComponent {
     }
 
     private isGetPropertySelected() {
-        return this.selectToscaFunction === ToscaGetFunctionType.GET_PROPERTY.toLowerCase();
+        return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_PROPERTY;
     }
 
     private isGetInputSelected() {
-        return this.selectToscaFunction === ToscaGetFunctionType.GET_INPUT.toLowerCase();
+        return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_INPUT;
     }
 
     private isComplexType(propertyType: string) {
@@ -185,7 +256,42 @@ export class ToscaFunctionComponent {
     }
 
     showDropdown(): boolean {
-        return this.selectToscaFunction && !this.isLoading && !this.dropDownErrorMsg;
+        if (this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_PROPERTY) {
+            return this.toscaGetFunction.propertySource && !this.isLoading && !this.dropDownErrorMsg;
+        }
+
+        return this.toscaGetFunction.functionType && !this.isLoading && !this.dropDownErrorMsg;
+    }
+
+    onPropertySourceChange() {
+        if (!this.toscaGetFunction.functionType || !this.propertySource) {
+            return;
+        }
+        this.toscaGetFunction.propertyUniqueId = undefined;
+        this.toscaGetFunction.propertyName = undefined;
+        this.toscaGetFunction.propertyPathFromSource = undefined;
+        if (this.propertySource === PropertySource.SELF) {
+            this.setSelfPropertySource();
+        } else {
+            this.toscaGetFunction.propertySource = PropertySource.INSTANCE;
+            this.toscaGetFunction.sourceName = this.propertySource;
+            this.toscaGetFunction.sourceUniqueId = this.instanceNameAndIdMap.get(this.propertySource);
+        }
+        this.loadDropdownValueLabel();
+        this.resetDropDown();
+        this.loadPropertiesInDropdown();
+    }
+
+    private setSelfPropertySource() {
+        this.toscaGetFunction.propertySource = PropertySource.SELF;
+        this.toscaGetFunction.sourceName = this.componentMetadata.name;
+        this.toscaGetFunction.sourceUniqueId = this.componentMetadata.uniqueId;
+    }
+
+    onPropertyChange() {
+        this.toscaGetFunction.propertyUniqueId = this.selectedProperty.propertyId;
+        this.toscaGetFunction.propertyName = this.selectedProperty.propertyName;
+        this.toscaGetFunction.propertyPathFromSource = this.selectedProperty.propertyPath;
     }
 
 }
@@ -194,6 +300,5 @@ export interface PropertyDropdownValue {
     propertyName: string;
     propertyId: string;
     propertyLabel: string;
-    toscaFunction: ToscaGetFunctionType;
     propertyPath: Array<string>;
 }
index 0aef293..d869a43 100644 (file)
   "DELETE_POLICY_MSG": "Are you sure you want to delete policy '{{policyName}}'?",
   "=========== PROPERTIES ASSIGNMENT TOSCA FUNCTION BUTTON ===========": "",
   "TOSCA_FUNCTION_LABEL": "TOSCA function",
+  "TOSCA_FUNCTION_PROPERTY_SOURCE_LABEL": "Property Source",
   "CLEAR_VALUE_LABEL": "Clear Value",
   "INPUT_DROPDOWN_LABEL": "Input",
   "TOSCA_FUNCTION_PROPERTY_DROPDOWN_LABEL": "Property",