Add metadata to topology inputs 74/116174/2 1.8.0
authorMichaelMorris <michael.morris@est.tech>
Fri, 27 Nov 2020 17:26:46 +0000 (17:26 +0000)
committerVasyl Razinkov <vasyl.razinkov@est.tech>
Tue, 15 Dec 2020 14:24:59 +0000 (14:24 +0000)
Change-Id: If57e16003532d59552fa0b5cacc69a792e5b877a
Issue-ID: SDC-3399
Signed-off-by: MichaelMorris <michael.morris@est.tech>
14 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaProperty.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogicTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/PropertyConvertorTest.java
catalog-ui/src/app/models/metadata.ts [new file with mode: 0644]
catalog-ui/src/app/models/metadataEntry.ts [new file with mode: 0644]
catalog-ui/src/app/models/properties-inputs/input-fe-model.ts
catalog-ui/src/app/models/properties-inputs/property-be-model.ts
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less
catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java

index d6459f4..c99b13a 100644 (file)
@@ -340,6 +340,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic {
                 String updateInputObjectValue = updateInputObjectValue(currInput, newInput, dataTypes);
                 currInput.setDefaultValue(updateInputObjectValue);
                 currInput.setOwnerId(userId);
+                currInput.setMetadata(newInput.getMetadata());
                 if (newInput.isRequired() != null) {
                     currInput.setRequired(newInput.isRequired());
                 }
index 4ccf7b1..4c4f19b 100644 (file)
@@ -105,6 +105,7 @@ public class PropertyConvertor {
         if(propertyType.equals(PropertyType.CAPABILITY)) {
             prop.setStatus(property.getStatus());
         }
+        prop.setMetadata(property.getMetadata());
         return prop;
     }
     
index fd3696e..952423e 100644 (file)
@@ -21,6 +21,7 @@
 package org.openecomp.sdc.be.tosca.model;
 
 import java.util.List;
+import java.util.Map;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
@@ -47,6 +48,9 @@ public class ToscaProperty {
     @Getter
     @Setter
     private String status;
+    @Getter
+    @Setter
+    private Map<String, String> metadata;
 
     public ToscaProperty(final ToscaProperty toscaProperty) {
         this.type = toscaProperty.type;
@@ -56,6 +60,7 @@ public class ToscaProperty {
         this.entry_schema = toscaProperty.entry_schema;
         this.status = toscaProperty.status;
         this.constraints = toscaProperty.constraints;
+        this.metadata = toscaProperty.metadata;
     }
 
     public Object getDefaultp() {
index 4b021c3..c83f73b 100644 (file)
@@ -764,6 +764,9 @@ public class InputsBusinessLogicTest {
         oldInputDef.setType(INPUT_TYPE);
         oldInputDef.setDefaultValue(OLD_VALUE);
         oldInputDef.setRequired(Boolean.FALSE);
+        Map<String, String> oldMetadata = new HashMap<>();
+        oldMetadata.put("key1", "value1");
+        oldInputDef.setMetadata(oldMetadata);
         oldInputDefs.add(oldInputDef);
         service.setInputs(oldInputDefs);
 
@@ -773,6 +776,10 @@ public class InputsBusinessLogicTest {
         inputDef.setType(INPUT_TYPE);
         inputDef.setDefaultValue(NEW_VALUE); // update value
         inputDef.setRequired(Boolean.TRUE); // update value
+        Map<String, String> newMetadata = new HashMap<>();
+        newMetadata.put("key1", "value2");
+        newMetadata.put("key2", "value3");
+        inputDef.setMetadata(newMetadata);
         newInputDefs.add(inputDef);
 
         // used in validateComponentExists
@@ -792,8 +799,11 @@ public class InputsBusinessLogicTest {
             testInstance.updateInputsValue(service.getComponentType(), COMPONENT_ID, newInputDefs, USER_ID, true, false);
         assertThat(result.isLeft()).isTrue();
         // check if values are updated
-        assertEquals(service.getInputs().get(0).getDefaultValue(), NEW_VALUE);
-        assertEquals(service.getInputs().get(0).isRequired(), Boolean.TRUE);
+        assertEquals(NEW_VALUE, service.getInputs().get(0).getDefaultValue());
+        assertEquals(Boolean.TRUE, service.getInputs().get(0).isRequired());
+        assertEquals(2, service.getInputs().get(0).getMetadata().size());
+        assertEquals("value2", service.getInputs().get(0).getMetadata().get("key1"));
+        assertEquals("value3", service.getInputs().get(0).getMetadata().get("key2"));
     }
 
 }
index d7c53d5..05ff278 100644 (file)
@@ -90,6 +90,16 @@ public class PropertyConvertorTest {
         assertNotNull(result);
         assertEquals(Integer.valueOf(def), result.getDefaultp());
     }
+    
+    @Test
+    public void convertPropertyWithMetadata() {
+        Map<String, String> metadata = new HashMap<>();
+        metadata.put("key1", "value");
+        property.setMetadata(metadata);
+        ToscaProperty result = propertyConvertor.convertProperty(dataTypes, property, PropertyConvertor.PropertyType.PROPERTY);
+        assertNotNull(result);
+        assertEquals(metadata, result.getMetadata());
+    }
 
     @Test
     public void convertPropertiesWhenValueAndDefaultNullInOne() {
diff --git a/catalog-ui/src/app/models/metadata.ts b/catalog-ui/src/app/models/metadata.ts
new file mode 100644 (file)
index 0000000..4db0800
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 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=========================================================
+ */
+
+'use strict';
+import * as _ from "lodash";
+
+export class Metadata {
+    
+    constructor(metaDataValues?:Metadata) {
+        _.forEach(metaDataValues, (metaDataValue:string, key) => {
+            this[key] = metaDataValue;
+        });
+    }
+}
+
diff --git a/catalog-ui/src/app/models/metadataEntry.ts b/catalog-ui/src/app/models/metadataEntry.ts
new file mode 100644 (file)
index 0000000..c8dddc8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 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=========================================================
+ */
+
+export class MetadataEntry {
+       public metaDataMapKey: string;
+       constructor(public key: string, public value: string) {
+               this.metaDataMapKey = key;
+       }
+}
\ No newline at end of file
index 85c514b..909f712 100644 (file)
@@ -24,6 +24,8 @@ import {PropertyFEModel} from "../../models";
 import {PROPERTY_DATA} from "../../utils/constants";
 import {InputBEModel} from "./input-be-model";
 import {DerivedPropertyType} from "./property-be-model";
+import { Metadata } from "app/models/metadata";
+import { MetadataEntry } from "app/models/metadataEntry";
 
 export class InputFEModel extends InputBEModel {
     isSimpleType: boolean;
@@ -35,6 +37,10 @@ export class InputFEModel extends InputBEModel {
     defaultValueObjIsChanged:boolean;
     derivedDataType: DerivedPropertyType;
     requiredOrig: boolean;
+    metadataOrig: Metadata;
+    metadataIsValid:boolean;
+    metadataEntries: MetadataEntry[] = [];
+    metadataMapKeyError: string;
 
     constructor(input?: InputBEModel) {
         super(input);
@@ -50,6 +56,14 @@ export class InputFEModel extends InputBEModel {
             this.updateDefaultValueObjOrig();
 
             this.requiredOrig = this.required;
+            this.metadataOrig = _.cloneDeep(input.metadata);
+            this.metadataIsValid = true;
+                       
+            if (input.metadata){
+                for (let key of Object.keys(input.metadata)){
+                    this.metadataEntries.push(new MetadataEntry(key, input.metadata[key]));
+                }
+            }
         }
     }
 
@@ -84,7 +98,66 @@ export class InputFEModel extends InputBEModel {
         return this.required !== this.requiredOrig;
     }
 
+    public updateMetadataKey(metadataEntry: MetadataEntry, newKey){
+        if (!newKey){
+               this.metadataIsValid = false;
+            this.metadataMapKeyError = 'Key cannot be empty.';
+            metadataEntry.key = newKey;
+            return;
+        } else if (metadataEntry.metaDataMapKey != newKey && this.metadata[newKey]){
+            this.metadataIsValid = false;
+            this.metadataMapKeyError = 'This key already exists!!.';
+            metadataEntry.key = newKey;
+            return;
+        }
+        this.metadataIsValid = true;
+        this.metadataMapKeyError = null;
+
+        if(metadataEntry.metaDataMapKey != newKey){
+            this.metadata[newKey] = _.cloneDeep(this.metadata[metadataEntry.metaDataMapKey]);
+            delete this.metadata[metadataEntry.metaDataMapKey];
+            metadataEntry.metaDataMapKey = newKey;
+        }
+        metadataEntry.key = newKey;  
+    }
+
+       public updateMetadataValue(metadataEntry: MetadataEntry, value: string){
+        metadataEntry.value = value;
+        this.metadata[metadataEntry.key] = value;
+       }
+
+    public addMetadataEntry(metadataEntry: MetadataEntry){
+        this.metadataEntries.push(metadataEntry);
+        if (!this.metadata){
+            this.metadata = new Metadata;
+        }
+        this.metadata[metadataEntry.key] = metadataEntry.value;
+    }
+       
+    public deleteMetadataEntry(metadataEntry: MetadataEntry){
+        let metadataEntryIndex = this.metadataEntries.findIndex(item => item.key === metadataEntry.key);
+        if (metadataEntryIndex != -1){
+            this.metadataEntries.splice(metadataEntryIndex, 1);
+        }
+        delete this.metadata[metadataEntry.key];
+    }
+
+    public resetMetadata = (): void => {
+        this.metadata =  _.cloneDeep(this.metadataOrig);
+        this.metadataIsValid = true;
+
+        this.metadataEntries = [];
+        for (let key of Object.keys(this.metadata)){
+            this.metadataEntries.push(new MetadataEntry(key, this.metadata[key]));
+        }
+    }
+    
+    hasMetadataChanged(): boolean {
+        return !_.isEqual(this.metadata, this.metadataOrig);
+    }
+
     hasChanged(): boolean {
-        return this.hasDefaultValueChanged() || this.hasRequiredChanged();
+        return this.hasDefaultValueChanged() || this.hasRequiredChanged() || this.hasMetadataChanged();
     }
+
 }
\ No newline at end of file
index 1d263bd..b997ea4 100644 (file)
@@ -22,6 +22,7 @@ import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils/constants';
 import { SchemaProperty, SchemaPropertyGroupModel } from '../aschema-property';
 import { ToscaPresentationData } from '../tosca-presentation';
 import { PropertyInputDetail } from './property-input-detail';
+import { Metadata } from '../metadata';
 
 export enum DerivedPropertyType {
     SIMPLE,
@@ -63,6 +64,7 @@ export class PropertyBEModel {
     subPropertyInputPath: string;
     inputPath: string;
     toscaPresentation: ToscaPresentationData;
+    metadata: Metadata;
 
     constructor(property?: PropertyBEModel) {
         if (property) {
@@ -87,6 +89,7 @@ export class PropertyBEModel {
             this.toscaPresentation = property.toscaPresentation;
             this.getPolicyValues = property.getPolicyValues;
             this.inputPath = property.inputPath;
+            this.metadata = property.metadata;
         }
 
         if (!this.schema || !this.schema.property) {
index d3db53a..ee09024 100644 (file)
@@ -32,6 +32,9 @@
         <div class="table-cell col4" (click)="sort('required')" *ngIf="componentType == 'SERVICE'">
             <span tooltip="Required in Runtime" tooltipDelay="400">Req. in RT</span>
         </div>
+        <div class="table-cell" [class.metadata-col-small]="!hasInputMetadata()" [class.metadata-col-wide]="hasInputMetadata()">
+            <div [class.metadata-col-wide-text]="hasInputMetadata()">Metadata</div>
+        </div>
         <div class="table-cell valueCol">Value</div>
     </div>
     <div class="table-body">
                         (checkedChange)="onRequiredChanged(input, $event)"
                         [disabled]="readonly"></sdc-checkbox>
                 </div>
+                <!-- Metadata -->
+                <div class="table-cell" [class.metadata-col-small]="!hasInputMetadata()" [class.metadataCol]="hasInputMetadata()">
+                    <div class="inner-cell-div metadata-add" tooltip="Add key value pair">
+                        <a class="property-icon add-item" (click)="createNewMetadataEntry(input);" [ngClass]="{'disabled':readonly}">Add metadata</a>
+                    </div>
+                    <ng-container >
+                        <div class="metadata-container">
+                        <ng-container *ngFor="let metadataEntry of input.metadataEntries;">
+                            <div  class="metadata-entry">
+                                    <ng-container>
+                                        <div class="metadata-key-value metadata-key" >
+                                            <dynamic-element #metadataViewChildren
+                                                class="value-input"
+                                                pattern="validationUtils.getValidationPattern(string)"
+                                                [value]="metadataEntry.key"
+                                                type="string"
+                                                name="{{input.name}}_{{metadataEntry.key}}"
+                                                (elementChanged)="onMetadataKeyChanged(input, $event, metadataEntry)"
+                                                [readonly]="readonly" 
+                                                [testId]="'prop-key-' + propertyTestsId"
+                                            ></dynamic-element>
+                                        </div>
+                                    </ng-container>
+                                    <ng-container>
+                                        <div class="metadata-key-value">
+                                            <dynamic-element
+                                                class="value-input"
+                                                pattern="validationUtils.getValidationPattern(string)"
+                                                [value]="metadataEntry.value"
+                                                type="string"
+                                                [name]="metadataEntry.key"
+                                                (elementChanged)="onMetadataValueChanged(input, $event, metadataEntry)"
+                                                [readonly]="readonly"
+                                                [testId]="'prop-key-' + propertyTestsId"
+                                        ></dynamic-element>
+                                        </div>
+                                        <span (click)="deleteMetadataEntry(input, metadataEntry);" class="delete-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}"></span>
+                                    </ng-container>
+                            </div>
+                        </ng-container>
+                        </div>
+                    </ng-container>
+                </div>
                 <!-- Value -->
-                <div class="table-cell valueCol input-value-col" [class.inner-table-container]="input.childrenProperties || !input.isSimpleType">
+                <div class="table-cell valueCol" [class.inner-table-container]="input.childrenProperties || !input.isSimpleType">
                     <dynamic-element class="value-input"
                                      *ngIf="checkInstanceFePropertiesMapIsFilled() && input.isSimpleType"
                                      pattern="validationUtils.getValidationPattern(input.type)"
                         <span *ngIf="input.instanceUniqueId && !readonly" class="sprite-new delete-btn" (click)="openDeleteModal(input)" data-tests-id="delete-input-button"></span>
                     </div>
                 </div>
-
             </div>
         </div>
     </div>
index 77c002c..74520b6 100644 (file)
@@ -3,6 +3,37 @@
 
 :host /deep/ input { width:100%;}
 
+.metadata-container {
+    .metadata-entry {
+        border-top:solid 1px #d2d2d2;
+        flex: 1;
+        display:flex;
+        flex-direction:row;
+        align-items: stretch;
+               
+        .metadata-key-value {
+            flex: 1;
+            padding:8px;
+            justify-content: center;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+        }
+
+        .metadata-key {
+            flex: 0 0 50%;
+            border-right:#d2d2d2 solid 1px;
+        }
+
+        .delete-icon {
+            flex: 0 0 auto;
+            margin-right:10px;
+            align-self:center;
+            cursor:pointer;
+        }
+    }
+}
+
 .properties-table {
     display:flex;
     flex-direction:column;
         }
         .valueCol {
             justify-content: flex-start;
+            padding: 10px 8px 10px 8px;
+        }
+
+        .metadata-col-small {
             padding: 10px;
+               flex: 0 0 115px;
+         }
+        .metadata-col-wide {
+            justify-content: flex-start;
+            padding: 0px;
+            flex: 1;
+
+           .metadata-col-wide-text {
+                   justify-content: flex-start;
+                   padding: 10px;
+                       }
         }
     }
     .table-header, .table-row {
         .selected-row {
             background-color:#e6f6fb;
         }
+        .table-cell.valueCol {
+            padding:8px;
+        }
+        .table-cell.metadataCol {
+            padding:0px;
+            .value-input {
+                flex: 1;
+                border: none;
+                background-color: inherit;
+
+                &:focus, &:active {
+                    border:none;
+                    outline:none;
+                }
+            }
+                       .metadata-add {
+                       padding: 10px;
+                       height: 40px;
+               }
+        }
+
+        .table-cell.metadata-col-small {
+               flex: 0 0 115px;
+            padding: 0px 10px 0px 10px;
+            .metadata-add {
+                padding: 10px 0px 10px 0px;
+                height: 40px;
+                margin-right: 0px;
+            }
+        }
+
     }
 
      .table-cell {
 
         // Column: Type
         &.col2 {
-            flex: 0 0 140px;
+            flex: 0 1 140px;
             max-width: 140px;
         }
 
         // Column: From Instance
         &.col3 {
-            flex: 0 0 120px;
+            flex: 0 1 120px;
             max-width: 120px;
         }
 
                 }
             }
         }
-
-         &.input-value-col {
-             padding: 8px;
-         }
-
-
     }
 
     .filtered {
index 682a3e2..3fa7ab4 100644 (file)
 /**
  * Created by rc2122 on 5/4/2017.
  */
-import { Component, Input, Output, EventEmitter } from "@angular/core";
+import { Component, Input, Output, EventEmitter, ViewChildren, QueryList } from "@angular/core";
 import { InputFEModel } from "app/models";
 import { ModalService } from "../../../services/modal.service";
 import { InstanceFeDetails } from "app/models/instance-fe-details";
 import { InstanceFePropertiesMap } from "../../../../models/properties-inputs/property-fe-map";
 import { DataTypeService } from "../../../services/data-type.service";
+import { MetadataEntry } from "app/models/metadataEntry";
+import { DynamicElementComponent } from "../../ui/dynamic-element/dynamic-element.component";
 
 @Component({
     selector: 'inputs-table',
@@ -41,10 +43,13 @@ export class InputsTableComponent {
     @Input() readonly: boolean;
     @Input() isLoading: boolean;
     @Input() componentType: string;
+    
     @Output() inputChanged: EventEmitter<any> = new EventEmitter<any>();
     @Output() deleteInput: EventEmitter<any> = new EventEmitter<any>();
 
     @Input() fePropertiesMap: InstanceFePropertiesMap;
+
+    @ViewChildren('metadataViewChildren') public metadataViewChildren: QueryList<DynamicElementComponent>;
     
     sortBy: String;
     reverse: boolean;
@@ -93,6 +98,35 @@ export class InputsTableComponent {
         this.inputChanged.emit(input);
     }
 
+    onMetadataKeyChanged = (input: InputFEModel, event, metadataEntry: MetadataEntry) => {
+        let dynamicElementComponent = this.metadataViewChildren.filter(element => element.name == input.name + "_" + metadataEntry.key).pop();
+
+        input.updateMetadataKey(metadataEntry, event.value);
+        this.inputChanged.emit(input);
+
+        var mapKeyError = input.metadataMapKeyError;
+        if(input.metadataMapKeyError){
+            dynamicElementComponent.cmpRef.instance.control.setErrors({mapKeyError});
+        } 
+    };
+
+    onMetadataValueChanged = (input: InputFEModel, event, metadataEntry: MetadataEntry) => {
+        input.updateMetadataValue(metadataEntry, event.value);
+        this.inputChanged.emit(input);
+    };
+    
+    
+    createNewMetadataEntry = (input: InputFEModel): void => {
+        let metadataEntry = new MetadataEntry("", "");
+        input.addMetadataEntry(metadataEntry);
+        this.inputChanged.emit(input);
+    }
+
+    deleteMetadataEntry = (input: InputFEModel, metadataEntry: MetadataEntry) => {
+        input.deleteMetadataEntry(metadataEntry);
+        this.inputChanged.emit(input);
+    }
+    
     onDeleteInput = () => {
         this.deleteInput.emit(this.selectedInputToDelete);
         this.modalService.closeCurrentModal();
@@ -100,8 +134,6 @@ export class InputsTableComponent {
 
     openDeleteModal = (input: InputFEModel) => {
         console.log('exist inputs: ' + this.inputs)
-        
-        
         this.selectedInputToDelete = input;
         this.modalService.createActionModal("Delete Input", "Are you sure you want to delete this input?", "Delete", this.onDeleteInput, "Close").instance.open();
     }
@@ -133,6 +165,16 @@ export class InputsTableComponent {
     checkInstanceFePropertiesMapIsFilled(){
         return _.keys(this.fePropertiesMap).length > 0
     }
+
+    hasInputMetadata(){
+        for(let input of this.inputs){
+            if (input.metadataEntries.length > 0){
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
 
 
index 83174fa..e4a8749 100644 (file)
@@ -367,7 +367,9 @@ export class PropertiesAssignmentComponent {
 
         if (this.isPropertiesTabSelected) {
             this.isValidChangedData = this.changedData.every((changedItem) => (<PropertyFEModel>changedItem).valueObjIsValid);
-        } else if (this.isInputsTabSelected || this.isPoliciesTabSelected) {
+        } else if (this.isInputsTabSelected) {
+            this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid && (<InputFEModel>changedItem).metadataIsValid);
+        } else if (this.isPoliciesTabSelected) {
             this.isValidChangedData = this.changedData.every((changedItem) => (<InputFEModel>changedItem).defaultValueObjIsValid);
         }
         this.updateHasChangedData();
@@ -846,6 +848,7 @@ export class PropertiesAssignmentComponent {
             handleReverseItem = (changedItem) => {
                 changedItem = <InputFEModel>changedItem;
                 this.inputsUtils.resetInputDefaultValue(changedItem, changedItem.defaultValue);
+                changedItem.resetMetadata();
                 changedItem.required = changedItem.requiredOrig;
             };
         }
index 5d9453a..d9e053f 100644 (file)
@@ -25,6 +25,7 @@ import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -32,6 +33,7 @@ import java.util.Set;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import org.apache.commons.collections.MapUtils;
 import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
 
 @EqualsAndHashCode(callSuper = false)
@@ -84,6 +86,8 @@ public class PropertyDataDefinition extends ToscaDataDefinition {
     private List<GetPolicyValueDataDefinition> getPolicyValues;
 
     private List<String> propertyConstraints;
+    
+    private Map<String, String> metadata;
 
     public PropertyDataDefinition() {
         super();
@@ -123,6 +127,9 @@ public class PropertyDataDefinition extends ToscaDataDefinition {
         if (isNotEmpty(propertyDataDefinition.annotations)) {
             this.setAnnotations(propertyDataDefinition.annotations);
         }
+        if (MapUtils.isNotEmpty(propertyDataDefinition.getMetadata())) {
+            setMetadata(new HashMap<>(propertyDataDefinition.getMetadata()));
+        }
         if(isNotEmpty(propertyDataDefinition.getPropertyConstraints())){
             setPropertyConstraints(new ArrayList<>(propertyDataDefinition.getPropertyConstraints()));
         }