Support for category specific metadata 25/116625/7
authorMichaelMorris <michael.morris@est.tech>
Tue, 15 Dec 2020 16:12:59 +0000 (16:12 +0000)
committerMichael Morris <michael.morris@est.tech>
Tue, 12 Jan 2021 16:35:48 +0000 (16:35 +0000)
Signed-off-by: MichaelMorris <michael.morris@est.tech>
Issue-ID: SDC-3412
Change-Id: I87392cc21dc25253b558bdc1d453d99659d049fa

35 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CategoriesImportManager.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplate.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplate.java
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaNodeTemplateTest.java
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateTest.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/GraphVertex.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java
catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/CategoryData.java
catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/category/SubCategoryData.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/Component.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/datamodel/ToscaElement.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/TopologyTemplateOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java
catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java
catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiServiceMetadata.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ToscaElementLifecycleOperationTest.java
catalog-ui/src/app/models/category.ts
catalog-ui/src/app/models/component-metadata.ts
catalog-ui/src/app/models/components/component.ts
catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap
catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html
catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts
catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts
catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html
catalog-ui/src/assets/languages/en_US.json
common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/CategoryDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/MetadataKeyDataDefinition.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/SubCategoryDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/GraphPropertyEnum.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/MetadataKeyEnum.java [new file with mode: 0644]

index 4330c0d..d49284e 100644 (file)
@@ -25,7 +25,9 @@ import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
 import org.openecomp.sdc.be.datamodel.api.CategoryTypeEnum;
 import org.openecomp.sdc.be.datamodel.utils.NodeTypeConvertUtils;
+import org.openecomp.sdc.be.datatypes.category.MetadataKeyDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.MetadataKeyEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.impl.ComponentsUtils;
 import org.openecomp.sdc.be.model.category.CategoryDefinition;
@@ -40,6 +42,7 @@ import org.springframework.stereotype.Component;
 import org.yaml.snakeyaml.Yaml;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -226,7 +229,7 @@ public class CategoriesImportManager {
     }
 
     private List<CategoryDefinition> createServiceCategories(Map<String, Object> categories) {
-        List<CategoryDefinition> categroiesDef = new ArrayList<>();
+        List<CategoryDefinition> categoriesDef = new ArrayList<>();
         String catName = null;
         List<String> icons = null;
         for (Entry<String, Object> entry : categories.entrySet()) {
@@ -242,10 +245,29 @@ public class CategoriesImportManager {
             final boolean useServiceSubstitutionForNestedServices = useServiceSubstitutionForNestedServicesProperty == null ? 
                     false : (Boolean) useServiceSubstitutionForNestedServicesProperty;
             catDef.setUseServiceSubstitutionForNestedServices(useServiceSubstitutionForNestedServices);
-            categroiesDef.add(catDef);
+            catDef.setMetadataKeys(getMetadataKeys(category));
+            categoriesDef.add(catDef);
         }
 
-        return categroiesDef;
+        return categoriesDef;
+    }
+    
+    private List<MetadataKeyDataDefinition> getMetadataKeys(Map<String, Object> parentObject) {
+        Map<String, Object> metadataKeys = (Map<String, Object>) parentObject.getOrDefault(MetadataKeyEnum.METADATA_KEYS.getName(), Collections.EMPTY_MAP);
+        List<MetadataKeyDataDefinition> metadataKeyDefs = new ArrayList<>();
+        for (Entry<String, Object> metadataKey : metadataKeys.entrySet()) {
+            Map<String, Object> metadataKeyInfo = (Map<String, Object>) metadataKey.getValue();
+            MetadataKeyDataDefinition metadataKeyDef = new MetadataKeyDataDefinition();
+            String metadataKeyName = (String) metadataKeyInfo.get(MetadataKeyEnum.NAME.getName());
+            metadataKeyDef.setName(metadataKeyName);
+            final Object mandatoryProperty = metadataKeyInfo.get(MetadataKeyEnum.MANDATORY.getName());
+            final boolean mandatory = mandatoryProperty == null ? false : (Boolean) mandatoryProperty;
+            metadataKeyDef.setMandatory(mandatory);
+            List<String> validValues = (List<String>) metadataKeyInfo.get(MetadataKeyEnum.VALID_VALUES.getName());
+            metadataKeyDef.setValidValues(validValues);
+            metadataKeyDefs.add(metadataKeyDef);
+        }
+        return metadataKeyDefs;
     }
 
     private List<CategoryDefinition> createResourceCategories(Map<String, Object> categoryPerType) {
@@ -268,6 +290,7 @@ public class CategoriesImportManager {
                 subDef.setIcons(subcategoryIcons);
                 normalizedName = ValidationUtils.normalizeCategoryName4Uniqueness(subcategoryName);
                 subDef.setNormalizedName(normalizedName);
+                subDef.setMetadataKeys(getMetadataKeys(subcategoryInfo));
                 subcateDef.add(subDef);
             }
 
index 5c8d9c6..6131eb5 100644 (file)
@@ -35,6 +35,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -67,6 +68,7 @@ import org.openecomp.sdc.be.datatypes.elements.RequirementSubstitutionFilterProp
 import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ToscaArtifactDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
 import org.openecomp.sdc.be.model.ArtifactDefinition;
@@ -410,37 +412,40 @@ public class ToscaExportHandler {
         }
     }
 
-    private ToscaMetadata convertMetadata(Component component) {
+    private Map<String, String> convertMetadata(Component component) {
         return convertMetadata(component, false, null);
     }
 
-    private ToscaMetadata convertMetadata(Component component, boolean isInstance,
+    private Map<String, String> convertMetadata(Component component, boolean isInstance,
                                           ComponentInstance componentInstance) {
-        ToscaMetadata toscaMetadata = new ToscaMetadata();
-        toscaMetadata.setInvariantUUID(component.getInvariantUUID());
-        toscaMetadata.setUUID(component.getUUID());
-        toscaMetadata.setDescription(component.getDescription());
-        toscaMetadata.setName(component.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
+        Map<String, String> toscaMetadata = new LinkedHashMap<>();
+        toscaMetadata.put(JsonPresentationFields.INVARIANT_UUID.getPresentation(), component.getInvariantUUID());
+        toscaMetadata.put(JsonPresentationFields.UUID.getPresentation(), component.getUUID());
+        toscaMetadata.put(JsonPresentationFields.NAME.getPresentation(), component.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
+        toscaMetadata.put(JsonPresentationFields.DESCRIPTION.getPresentation(), component.getDescription());
 
         List<CategoryDefinition> categories = component.getCategories();
         CategoryDefinition categoryDefinition = categories.get(0);
-        toscaMetadata.setCategory(categoryDefinition.getName());
+        toscaMetadata.put(JsonPresentationFields.CATEGORY.getPresentation(), categoryDefinition.getName());
 
         if (isInstance) {
-            toscaMetadata.setVersion(component.getVersion());
-            toscaMetadata.setCustomizationUUID(componentInstance.getCustomizationUUID());
+            toscaMetadata.put(JsonPresentationFields.VERSION.getPresentation(),component.getVersion());
+            toscaMetadata.put(JsonPresentationFields.CUSTOMIZATION_UUID.getPresentation(), componentInstance.getCustomizationUUID());
             if (componentInstance.getSourceModelInvariant() != null
                 && !componentInstance.getSourceModelInvariant().isEmpty()) {
-                toscaMetadata.setVersion(componentInstance.getComponentVersion());
-                toscaMetadata.setSourceModelInvariant(componentInstance.getSourceModelInvariant());
-                toscaMetadata.setSourceModelUuid(componentInstance.getSourceModelUuid());
-                toscaMetadata.setSourceModelName(componentInstance.getSourceModelName());
+                toscaMetadata.put(JsonPresentationFields.VERSION.getPresentation(),componentInstance.getComponentVersion());
+                toscaMetadata.put(JsonPresentationFields.CI_SOURCE_MODEL_INVARIANT.getPresentation(),componentInstance.getSourceModelInvariant());
+                toscaMetadata.put(JsonPresentationFields.CI_SOURCE_MODEL_UUID.getPresentation(),componentInstance.getSourceModelUuid());
+                toscaMetadata.put(JsonPresentationFields.CI_SOURCE_MODEL_NAME.getPresentation(),componentInstance.getSourceModelName());
                 if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) {
-                       toscaMetadata.setName(componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceProxy.getDisplayValue());
+                    toscaMetadata.put(JsonPresentationFields.NAME.getPresentation(),
+                        componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceProxy.getDisplayValue());
                 } else if (componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) {
-                    toscaMetadata.setName(componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceSubstitution.getDisplayValue());
+                    toscaMetadata.put(JsonPresentationFields.NAME.getPresentation(),
+                        componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceSubstitution
+                            .getDisplayValue());
                 }
-                toscaMetadata.setDescription(componentInstance.getDescription());
+                toscaMetadata.put(JsonPresentationFields.DESCRIPTION.getPresentation(),componentInstance.getDescription());
             }
 
         }
@@ -449,33 +454,37 @@ public class ToscaExportHandler {
                 Resource resource = (Resource) component;
 
             if (isInstance && (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution)) {
-                    toscaMetadata.setType(componentInstance.getOriginType().getDisplayValue());
+                    toscaMetadata.put(JsonPresentationFields.TYPE.getPresentation(), componentInstance.getOriginType().getDisplayValue());
                 } else {
-                    toscaMetadata.setType(resource.getResourceType().name());
+                    toscaMetadata.put(JsonPresentationFields.TYPE.getPresentation(), resource.getResourceType().name());
                 }
-                toscaMetadata.setSubcategory(categoryDefinition.getSubcategories().get(0).getName());
-                toscaMetadata.setResourceVendor(resource.getVendorName());
-                toscaMetadata.setResourceVendorRelease(resource.getVendorRelease());
-                toscaMetadata.setResourceVendorModelNumber(resource.getResourceVendorModelNumber());
+                toscaMetadata.put(JsonPresentationFields.SUB_CATEGORY.getPresentation(), categoryDefinition.getSubcategories().get(0).getName());
+                toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR.getPresentation(), resource.getVendorName());
+                toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_RELEASE.getPresentation(),resource.getVendorRelease());
+                toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_MODEL_NUMBER.getPresentation(),resource.getResourceVendorModelNumber());
                 break;
             case SERVICE:
                 Service service = (Service) component;
-                toscaMetadata.setType(component.getComponentType().getValue());
-                toscaMetadata.setServiceType(service.getServiceType());
-                toscaMetadata.setServiceRole(service.getServiceRole());
-                toscaMetadata.setServiceFunction(service.getServiceFunction());
-                toscaMetadata.setEnvironmentContext(service.getEnvironmentContext());
-                resolveInstantiationTypeAndSetItToToscaMetaData(toscaMetadata, service);
+                toscaMetadata.put(JsonPresentationFields.TYPE.getPresentation(),component.getComponentType().getValue());
+                toscaMetadata.put(JsonPresentationFields.SERVICE_TYPE.getPresentation(),service.getServiceType());
+                toscaMetadata.put(JsonPresentationFields.SERVICE_ROLE.getPresentation(),service.getServiceRole());
+                toscaMetadata.put(JsonPresentationFields.SERVICE_FUNCTION.getPresentation(),service.getServiceFunction());
+                toscaMetadata.put(JsonPresentationFields.ENVIRONMENT_CONTEXT.getPresentation(),service.getEnvironmentContext());
+                toscaMetadata.put(JsonPresentationFields.INSTANTIATION_TYPE.getPresentation(),service.getEnvironmentContext() == null ? StringUtils.EMPTY : service.getInstantiationType());
                 if (!isInstance) {
                     // DE268546
-                    toscaMetadata.setServiceEcompNaming(((Service) component).isEcompGeneratedNaming());
-                    toscaMetadata.setEcompGeneratedNaming(((Service) component).isEcompGeneratedNaming());
-                    toscaMetadata.setNamingPolicy(((Service) component).getNamingPolicy());
+                    toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(),service.isEcompGeneratedNaming().toString()); 
+                    toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(),service.isEcompGeneratedNaming().toString());
+                    toscaMetadata.put(JsonPresentationFields.NAMING_POLICY.getPresentation(),service.getNamingPolicy());
                 }
                 break;
             default:
                 log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType());
         }
+        
+        for (final String key: component.getCategorySpecificMetadata().keySet()) {
+            toscaMetadata.put(key, component.getCategorySpecificMetadata().get(key));
+        }
         return toscaMetadata;
     }
 
index 04515b2..50a8f3d 100644 (file)
@@ -37,7 +37,7 @@ public class ToscaNodeTemplate {
 
     private String type;
     private List<String> directives;
-    private ToscaMetadata metadata;
+    private Map<String, String> metadata;
     private String description;
     private Map<String, Object> properties;
     private List<Map<String, ToscaTemplateRequirement>> requirements;
index 742e8bb..7fc60d1 100644 (file)
 
 package org.openecomp.sdc.be.tosca.model;
 
-import org.apache.commons.lang3.tuple.Triple;
-import org.openecomp.sdc.be.model.Component;
-
 import java.util.List;
 import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.tuple.Triple;
+import org.openecomp.sdc.be.model.Component;
 
+@Getter
+@Setter
 public class ToscaTemplate {
 
     private String tosca_definitions_version;
-    private ToscaMetadata metadata;
+    private Map<String, String> metadata;
     private List<Map<String, Map<String, String>>> imports;
     private Map<String, Object> interface_types;
     private Map<String, ToscaDataType> data_types;
     private Map<String, ToscaNodeType> node_types;
     private ToscaTopolgyTemplate topology_template;
-
     private List<Triple<String, String, Component>> dependencies;
 
-    public ToscaTemplate(String tosca_definitions_version) {
-        this.tosca_definitions_version = tosca_definitions_version;
-    }
-
-    public Map<String, ToscaNodeType> getNode_types() {
-        return node_types;
-    }
-
-    public void setNode_types(Map<String, ToscaNodeType> node_types) {
-        this.node_types = node_types;
-    }
-
-
-    public List<Map<String, Map<String, String>>> getImports() {
-        return imports;
-    }
-
-    public void setImports(List<Map<String, Map<String, String>>> imports) {
-        this.imports = imports;
-    }
-
-    public String getTosca_definitions_version() {
-        return tosca_definitions_version;
-    }
-
-    public void setTosca_definitions_version(String tosca_definitions_version) {
-        this.tosca_definitions_version = tosca_definitions_version;
-    }
-
-    public ToscaMetadata getMetadata() {
-        return metadata;
-    }
-
-    public void setMetadata(ToscaMetadata metadata) {
-        this.metadata = metadata;
-    }
-
-    public ToscaTopolgyTemplate getTopology_template() {
-        return topology_template;
-    }
-
-    public void setTopology_template(ToscaTopolgyTemplate topology_template) {
-        this.topology_template = topology_template;
-    }
-
-    public List<Triple<String, String, Component>> getDependencies() {
-        return dependencies;
-    }
-
-    public void setDependencies(List<Triple<String, String, Component>> dependencies) {
-        this.dependencies = dependencies;
-    }
-
-    public Map<String, Object> getInterface_types() {
-        return interface_types;
-    }
-
-    //    public void setInterface_types(Map<String, Object> interface_types) {
-    //        this.interface_types = interface_types;
-    //    }
-
-    public void setInterface_types(Map<String, Object> interface_types) {
-        this.interface_types = interface_types;
-
+    public ToscaTemplate(final String toscaDefinitionsVersion) {
+        this.tosca_definitions_version = toscaDefinitionsVersion;
     }
 
-    /**
-     * Gets data_types map.
-     * @return Current data_types map.
-     */
-    public Map<String, ToscaDataType> getData_types() {
-        return data_types;
-    }
-
-    /**
-     * Sets data_types map.
-     * @param data_types New data_types map.
-     */
-    public void setData_types(Map<String, ToscaDataType> data_types) {
-        this.data_types = data_types;
-    }
 }
 
index d54fc98..b03e12f 100644 (file)
@@ -433,10 +433,8 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
         componentInstance.setOriginType(OriginTypeEnum.ServiceProxy);
         componentInstance.setSourceModelInvariant("targetModelInvariant");
 
-        ToscaMetadata result;
-
         // default test
-        result = Deencapsulation.invoke(testSubject, "convertMetadata", component, isInstance, componentInstance);
+        Map<String, String> result = Deencapsulation.invoke(testSubject, "convertMetadata", component, isInstance, componentInstance);
         Assert.assertNotNull(result);
     }
 
index 7c28e9f..e8f53f0 100644 (file)
@@ -124,7 +124,7 @@ public class ToscaNodeTemplateTest {
        @Test
        public void testGetMetadata() throws Exception {
                ToscaNodeTemplate testSubject;
-               ToscaMetadata result;
+               Map<String, String> result;
 
                // default test
                testSubject = createTestSubject();
@@ -135,7 +135,7 @@ public class ToscaNodeTemplateTest {
        @Test
        public void testSetMetadata() throws Exception {
                ToscaNodeTemplate testSubject;
-               ToscaMetadata metadata = null;
+               Map<String, String> metadata = null;
 
                // default test
                testSubject = createTestSubject();
index 36674a7..13bb415 100644 (file)
@@ -104,7 +104,7 @@ public class ToscaTemplateTest {
        @Test
        public void testGetMetadata() throws Exception {
                ToscaTemplate testSubject;
-               ToscaMetadata result;
+               Map<String, String> result;
 
                // default test
                testSubject = createTestSubject();
@@ -115,7 +115,7 @@ public class ToscaTemplateTest {
        @Test
        public void testSetMetadata() throws Exception {
                ToscaTemplate testSubject;
-               ToscaMetadata metadata = null;
+               Map<String, String> metadata = null;
 
                // default test
                testSubject = createTestSubject();
index 11dcdce..f3e64b1 100644 (file)
@@ -167,6 +167,20 @@ public class GraphVertex {
                }
                return null;
        }
+       
+   public void setJsonMetadataField(String field, Object value) {
+        if (metadataJson == null) {
+            metadataJson = new HashMap<>();
+        }
+        metadataJson.put(field, value);
+    }
+
+    public Object getJsonMetadataField(String field) {
+        if (metadataJson != null) {
+            return metadataJson.get(field);
+        }
+        return null;
+    }
 
        /**
         * Updates metadata json with current metadataProperties. Note that already existing property containing in metadata json can be overrided by new value if metadataProperties contains the same property (by key). Note that metadata json can contain
index da6e5d5..8581895 100644 (file)
@@ -126,7 +126,8 @@ public enum GraphPropertiesDictionary {
        CONSTANT_UUID           ("constantUuidNew",                     String.class,               false,              true),
        CONTACTS                        ("contacts",                            String.class,                           false,          false),
        //categorys
-       ICONS                           ("icons",                                       String.class,                           false,          false),
+       ICONS               ("icons",                   String.class,               false,      false),
+       METADATA_KEYS       ("metadataKeys",            String.class,               false,      false),
        USE_SERVICE_SUBSTITUTION_FOR_NESTED_SERVICES   ("useServiceSubstitutionForNestedServices",      Boolean.class,                 false,      false),
        //relation
        CAPABILITY_OWNER_ID     ("capOwnerId",                          String.class,                           false,          false),
index 8db7b53..613f91d 100644 (file)
@@ -24,6 +24,7 @@ import com.google.gson.reflect.TypeToken;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
 import org.openecomp.sdc.be.datatypes.category.CategoryDataDefinition;
+import org.openecomp.sdc.be.datatypes.category.MetadataKeyDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 
 import java.lang.reflect.Type;
@@ -60,6 +61,11 @@ public class CategoryData extends GraphNode {
                List<String> iconsfromJson = getGson()
                                .fromJson((String) properties.get(GraphPropertiesDictionary.ICONS.getProperty()), listType);
                categoryDataDefinition.setIcons(iconsfromJson);
+               
+               final Type metadataKeylistType = new TypeToken<List<MetadataKeyDataDefinition>>() {}.getType();
+               final List<MetadataKeyDataDefinition> metadataKeysfromJson = getGson()
+                       .fromJson((String) properties.get(GraphPropertiesDictionary.METADATA_KEYS.getProperty()), metadataKeylistType);
+               categoryDataDefinition.setMetadataKeys(metadataKeysfromJson);
        }
 
        @Override
@@ -82,6 +88,7 @@ public class CategoryData extends GraphNode {
                // addIfExists(map, GraphPropertiesDictionary.ICONS, icons);
         addIfExists(map, GraphPropertiesDictionary.ICONS, categoryDataDefinition.getIcons());
         addIfExists(map, GraphPropertiesDictionary.USE_SERVICE_SUBSTITUTION_FOR_NESTED_SERVICES, categoryDataDefinition.isUseServiceSubstitutionForNestedServices());
+        addIfExists(map, GraphPropertiesDictionary.METADATA_KEYS, categoryDataDefinition.getMetadataKeys());
                return map;
        }
 
index cbae456..1397603 100644 (file)
@@ -23,6 +23,7 @@ package org.openecomp.sdc.be.resources.data.category;
 import com.google.gson.reflect.TypeToken;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
+import org.openecomp.sdc.be.datatypes.category.MetadataKeyDataDefinition;
 import org.openecomp.sdc.be.datatypes.category.SubCategoryDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 
@@ -59,6 +60,11 @@ public class SubCategoryData extends GraphNode {
                List<String> iconsfromJson = getGson()
                                .fromJson((String) properties.get(GraphPropertiesDictionary.ICONS.getProperty()), listType);
                subCategoryDataDefinition.setIcons(iconsfromJson);
+               
+               final Type metadataKeylistType = new TypeToken<List<MetadataKeyDataDefinition>>() {}.getType();
+               final List<MetadataKeyDataDefinition> metadataKeysfromJson = getGson()
+                       .fromJson((String) properties.get(GraphPropertiesDictionary.METADATA_KEYS.getProperty()), metadataKeylistType);
+               subCategoryDataDefinition.setMetadataKeys(metadataKeysfromJson);
        }
 
        public SubCategoryDataDefinition getSubCategoryDataDefinition() {
@@ -80,6 +86,7 @@ public class SubCategoryData extends GraphNode {
                // String icons=getGson().toJson(subCategoryDataDefinition.getIcons());
                // addIfExists(map, GraphPropertiesDictionary.ICONS, icons);
                addIfExists(map, GraphPropertiesDictionary.ICONS, subCategoryDataDefinition.getIcons());
+               addIfExists(map, GraphPropertiesDictionary.METADATA_KEYS, subCategoryDataDefinition.getMetadataKeys());
                return map;
        }
 }
index bf9c327..7b188ac 100644 (file)
@@ -29,6 +29,7 @@ import static org.apache.commons.collections.MapUtils.isEmpty;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.google.common.collect.Maps;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -89,6 +90,14 @@ public abstract class Component implements PropertiesOwner {
     private Map<String, InterfaceDefinition> interfaces;
     private List<DataTypeDefinition> dataTypes;
     private SubstitutionFilterDataDefinition substitutionFilter;
+    
+    public void setCategorySpecificMetadata(final Map<String, String> categorySpecificMetadata) {
+        componentMetadataDefinition.getMetadataDataDefinition().setCategorySpecificMetadata(categorySpecificMetadata);
+    }
+    public Map<String, String> getCategorySpecificMetadata() {
+        final Map<String, String> categorySpecificMetadata = componentMetadataDefinition.getMetadataDataDefinition().getCategorySpecificMetadata();
+        return categorySpecificMetadata == null ? Collections.emptyMap() : categorySpecificMetadata;
+    }
 
     public Component(ComponentMetadataDefinition componentMetadataDefinition) {
         this.componentMetadataDefinition = componentMetadataDefinition;
index ce9e5e0..baea051 100644 (file)
@@ -85,11 +85,14 @@ public abstract class ToscaElement {
     }
 
     public void setMetadataValue(JsonPresentationFields name, Object value) {
+        setMetadataValue(name.getPresentation(), value);
+    }
+    
+    public void setMetadataValue(String name, Object value) {
         if (metadata == null) {
             metadata = new HashMap<>();
         }
-        metadata.put(name.getPresentation(), value);
-
+        metadata.put(name, value);
     }
     // --------------------
     public String getUUID() {
index 3109107..76f952b 100644 (file)
@@ -39,6 +39,7 @@ import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
+import org.openecomp.sdc.be.datatypes.category.MetadataKeyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.MapCapabilityProperty;
 import org.openecomp.sdc.be.datatypes.elements.MapListCapabilityDataDefinition;
@@ -1189,6 +1190,11 @@ public class TopologyTemplateOperation extends ToscaElementOperation {
         Type listTypeCat = new TypeToken<List<String>>() {}.getType();
         List<String> iconsfromJsonCat = getGson().fromJson((String) metadataProperties.get(GraphPropertyEnum.ICONS.getProperty()), listTypeCat);
         category.setIcons(iconsfromJsonCat);
+        
+        final Type metadataKeysTypeCat = new TypeToken<List<MetadataKeyDataDefinition>>() {}.getType();
+        final List<MetadataKeyDataDefinition> metadataKeysfromJsonCat = getGson().fromJson((String) metadataProperties.get(GraphPropertyEnum.METADATA_KEYS), metadataKeysTypeCat);
+        category.setMetadataKeys(metadataKeysfromJsonCat);
+        
         categories.add(category);
         toscaElement.setCategories(categories);
 
index bc77d20..3ae39fd 100644 (file)
@@ -54,6 +54,7 @@ import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
 import org.openecomp.sdc.be.dao.jsongraph.utils.JsonParserUtils;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
+import org.openecomp.sdc.be.datatypes.category.MetadataKeyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.AdditionalInfoParameterDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
@@ -330,7 +331,7 @@ public abstract class ToscaElementOperation extends BaseOperation {
         nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.IS_ARCHIVED, toscaElement.getMetadataValue(JsonPresentationFields.IS_ARCHIVED));
         nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.ARCHIVE_TIME, toscaElement.getMetadataValue(JsonPresentationFields.ARCHIVE_TIME));
         nodeTypeVertex.addMetadataProperty(GraphPropertyEnum.IS_VSP_ARCHIVED, toscaElement.getMetadataValue(JsonPresentationFields.IS_VSP_ARCHIVED));
-        toscaElement.getMetadata().entrySet().stream().filter(e -> e.getValue() != null).forEach(e -> nodeTypeVertex.setJsonMetadataField(JsonPresentationFields.getByPresentation(e.getKey()), e.getValue()));
+        toscaElement.getMetadata().entrySet().stream().filter(e -> e.getValue() != null).forEach(e -> nodeTypeVertex.setJsonMetadataField(e.getKey(), e.getValue()));
 
         nodeTypeVertex.setUniqueId(toscaElement.getUniqueId());
         nodeTypeVertex.setType(toscaElement.getComponentType());
@@ -1046,6 +1047,12 @@ public abstract class ToscaElementOperation extends BaseOperation {
         subcategory.setUniqueId((String) subCategoryV.property(GraphPropertyEnum.UNIQUE_ID.getProperty()).value());
         subcategory.setNormalizedName(subCategoryNormalizedName);
         subcategory.setName((String) subCategoryV.property(GraphPropertyEnum.NAME.getProperty()).value());
+        
+        Type listTypeSubcat = new TypeToken<List<MetadataKeyDataDefinition>>() {
+        }.getType();
+        List<MetadataKeyDataDefinition> metadataKeys = getGson().fromJson((String) subCategoryV.property(GraphPropertyEnum.METADATA_KEYS.getProperty()).value(), listTypeSubcat);
+        subcategory.setMetadataKeys(metadataKeys);
+        
         Either<Vertex, JanusGraphOperationStatus> parentVertex = janusGraphDao.getParentVertex(subCategoryV, EdgeLabelEnum.SUB_CATEGORY, JsonParseFlagEnum.NoParse);
         Vertex categoryV = parentVertex.left().value();
         String categoryNormalizedName = (String) categoryV.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()).value();
@@ -1077,6 +1084,11 @@ public abstract class ToscaElementOperation extends BaseOperation {
         category.setName((String) categoryV.property(GraphPropertyEnum.NAME.getProperty()).value());
         category.setUseServiceSubstitutionForNestedServices((Boolean) categoryV.property(GraphPropertyEnum.USE_SUBSTITUTION_FOR_NESTED_SERVICES.getProperty()).orElse(false));
 
+        Type listTypeCat = new TypeToken<List<MetadataKeyDataDefinition>>() {
+        }.getType();
+        List<MetadataKeyDataDefinition> metadataKeys = getGson().fromJson((String) categoryV.property(GraphPropertyEnum.METADATA_KEYS.getProperty()).value(), listTypeCat);
+        category.setMetadataKeys(metadataKeys);
+        
         categories.add(category);
         catalogComponent.setCategories(categories);
         return JanusGraphOperationStatus.OK;
@@ -1104,6 +1116,10 @@ public abstract class ToscaElementOperation extends BaseOperation {
         List<String> iconsfromJsonSubcat = getGson().fromJson((String) metadataProperties.get(GraphPropertyEnum.ICONS), listTypeSubcat);
         subcategory.setIcons(iconsfromJsonSubcat);
 
+        final Type metadataKeysTypeCat = new TypeToken<List<MetadataKeyDataDefinition>>() {}.getType();
+        final List<MetadataKeyDataDefinition> metadataKeysfromJsonCat = getGson().fromJson((String) metadataProperties.get(GraphPropertyEnum.METADATA_KEYS), metadataKeysTypeCat);
+        subcategory.setMetadataKeys(metadataKeysfromJsonCat);
+  
         Either<GraphVertex, JanusGraphOperationStatus> parentVertex = janusGraphDao
             .getParentVertex(subCategoryV, EdgeLabelEnum.SUB_CATEGORY, JsonParseFlagEnum.NoParse);
         if (parentVertex.isRight()) {
index 146d5d6..bbda977 100644 (file)
@@ -39,10 +39,12 @@ import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.openecomp.sdc.be.config.ConfigurationManager;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionaryExtractor;
+import org.openecomp.sdc.be.datatypes.category.MetadataKeyDataDefinition;
 import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition;
 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
 import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition;
@@ -105,6 +107,8 @@ import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
 import org.openecomp.sdc.be.model.RequirementDefinition;
 import org.openecomp.sdc.be.model.Resource;
 import org.openecomp.sdc.be.model.Service;
+import org.openecomp.sdc.be.model.category.CategoryDefinition;
+import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.NodeType;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
@@ -776,6 +780,7 @@ public class ModelConverter {
             } else {
                 resource.setResourceVendorModelNumber("");
             }
+            
         } else if (component.getComponentType() == ComponentTypeEnum.SERVICE) {
             Service service = (Service) component;
             if (((String) toscaElement.getMetadataValue(JsonPresentationFields.SERVICE_TYPE)) != null){
@@ -803,6 +808,41 @@ public class ModelConverter {
         component.setUUID((String) toscaElement.getMetadataValue(JsonPresentationFields.UUID));
         component.setIsDeleted((Boolean) toscaElement.getMetadataValue(JsonPresentationFields.IS_DELETED));
         component.setToscaType(toscaElement.getToscaType().getValue());
+        final List<String> metadataKeys = getCategorySpecificMetadataKeys(toscaElement);
+        if (CollectionUtils.isNotEmpty(metadataKeys)) {
+            final Map<String, String> categorySpecificMetadata = new HashMap<>();
+            for (final String metadataKey: metadataKeys) {
+                categorySpecificMetadata.put(metadataKey, (String) toscaElement.getMetadata().get(metadataKey));
+            }
+            component.setCategorySpecificMetadata(categorySpecificMetadata );
+        }
+    }
+    
+    private static List<String> getCategorySpecificMetadataKeys(final ToscaElement toscaElement){
+        final List<String> metadataKeys = new ArrayList<>();
+        final Optional<CategoryDefinition> category = getCategory(toscaElement);
+        if (category.isPresent()) {
+            if (CollectionUtils.isNotEmpty(category.get().getMetadataKeys())) {
+                for (final MetadataKeyDataDefinition metadataKey: category.get().getMetadataKeys()) {
+                    metadataKeys.add(metadataKey.getName());
+                }
+            }
+            final Optional<SubCategoryDefinition> subCategory = getSubCategory(category.get());
+            if (subCategory.isPresent() && CollectionUtils.isNotEmpty(subCategory.get().getMetadataKeys())) {
+                for (final MetadataKeyDataDefinition metadataKey: subCategory.get().getMetadataKeys()) {
+                    metadataKeys.add(metadataKey.getName());
+                }
+            }
+        }
+        return metadataKeys;
+    }
+    
+    private static Optional<CategoryDefinition> getCategory(ToscaElement toscaElement) {
+        return CollectionUtils.isEmpty(toscaElement.getCategories()) ? Optional.empty() : Optional.of(toscaElement.getCategories().get(0));
+    }
+    
+    private static Optional<SubCategoryDefinition> getSubCategory(CategoryDefinition category) {
+        return CollectionUtils.isEmpty(category.getSubcategories()) ? Optional.empty() : Optional.of(category.getSubcategories().get(0));
     }
 
     private static NodeType convertToNodeType(Component component) {
@@ -1345,6 +1385,10 @@ public class ModelConverter {
         toscaElement.setMetadataValue(JsonPresentationFields.TAGS, component.getTags());
         toscaElement.setMetadataValue(JsonPresentationFields.INVARIANT_UUID, component.getInvariantUUID());
         toscaElement.setMetadataValue(JsonPresentationFields.CONTACT_ID, component.getContactId());
+        for (final String key: component.getCategorySpecificMetadata().keySet()) {
+            toscaElement.setMetadataValue(key, component.getCategorySpecificMetadata().get(key));       
+        }
+
         final List<DataTypeDefinition> dataTypes = component.getDataTypes();
         if (CollectionUtils.isNotEmpty(dataTypes)) {
             toscaElement.setDataTypes(dataTypes.stream()
index c8d7bdf..971f966 100644 (file)
@@ -21,6 +21,7 @@
 package org.openecomp.sdc.be.ui.model;
 
 import java.util.List;
+import java.util.Map;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
@@ -42,6 +43,7 @@ public class UiResourceMetadata extends UiComponentMetadata {
     private String licenseType;
     private String toscaResourceName;
     private List<String> derivedFrom;
+    private Map<String, String> categorySpecificMetadata;
 
 
     public UiResourceMetadata(List<CategoryDefinition> categories, List<String> derivedFrom,
@@ -55,6 +57,7 @@ public class UiResourceMetadata extends UiComponentMetadata {
         this.licenseType = metadata.getLicenseType();
         this.toscaResourceName = metadata.getToscaResourceName();
         this.derivedFrom = derivedFrom;
+        this.categorySpecificMetadata = metadata.getCategorySpecificMetadata();
     }
 
 }
index e1fe587..6aec7bc 100644 (file)
@@ -21,6 +21,7 @@
 package org.openecomp.sdc.be.ui.model;
 
 import java.util.List;
+import java.util.Map;
 import lombok.Getter;
 import lombok.Setter;
 import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition;
@@ -38,6 +39,7 @@ public class UiServiceMetadata extends UiComponentMetadata {
     private String environmentContext;
     private String instantiationType;
     private String serviceFunction;
+    private Map<String, String> categorySpecificMetadata;
 
     public UiServiceMetadata(List<CategoryDefinition> categories, ServiceMetadataDataDefinition metadata) {
         super(categories, metadata);
@@ -49,6 +51,7 @@ public class UiServiceMetadata extends UiComponentMetadata {
         this.environmentContext = metadata.getEnvironmentContext();
         this.instantiationType = metadata.getInstantiationType();
         this.serviceFunction = metadata.getServiceFunction();
+        this.categorySpecificMetadata = metadata.getCategorySpecificMetadata();
     }
 
 }
index a8a201d..654b074 100644 (file)
@@ -303,6 +303,7 @@ public class ToscaElementLifecycleOperationTest extends ModelTestBase {
         metadataProperties.put(GraphPropertyEnum.LABEL, VertexTypeEnum.RESOURCE_CATEGORY.getName());
         metadataProperties.put(GraphPropertyEnum.NAME, categoryName);
         metadataProperties.put(GraphPropertyEnum.NORMALIZED_NAME, ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
+        metadataProperties.put(GraphPropertyEnum.METADATA_KEYS, "[]");
         cat.setMetadataProperties(metadataProperties);
         cat.updateMetadataJsonWithCurrentMetadataProperties();
 
@@ -314,6 +315,7 @@ public class ToscaElementLifecycleOperationTest extends ModelTestBase {
         metadataProperties.put(GraphPropertyEnum.LABEL, VertexTypeEnum.RESOURCE_SUBCATEGORY.getName());
         metadataProperties.put(GraphPropertyEnum.NAME, subcategory);
         metadataProperties.put(GraphPropertyEnum.NORMALIZED_NAME, ValidationUtils.normalizeCategoryName4Uniqueness(subcategory));
+        metadataProperties.put(GraphPropertyEnum.METADATA_KEYS, "[]");
         subCat.setMetadataProperties(metadataProperties);
         subCat.updateMetadataJsonWithCurrentMetadataProperties();
 
@@ -337,6 +339,7 @@ public class ToscaElementLifecycleOperationTest extends ModelTestBase {
         metadataProperties.put(GraphPropertyEnum.LABEL, VertexTypeEnum.SERVICE_CATEGORY.getName());
         metadataProperties.put(GraphPropertyEnum.NAME, categoryName);
         metadataProperties.put(GraphPropertyEnum.NORMALIZED_NAME, ValidationUtils.normalizeCategoryName4Uniqueness(categoryName));
+        metadataProperties.put(GraphPropertyEnum.METADATA_KEYS, "[]");
         cat.setMetadataProperties(metadataProperties);
         cat.updateMetadataJsonWithCurrentMetadataProperties();
 
index 15df985..64588d0 100644 (file)
@@ -28,6 +28,7 @@ export interface ICategoryBase {
     normalizedName:string;
     uniqueId:string;
     icons:Array<string>;
+    metadataKeys: IMetadataKey[];
 
     //custom properties
     filterTerms:string;
@@ -46,3 +47,9 @@ export interface ISubCategory extends ICategoryBase {
 
 export interface IGroup extends ICategoryBase {
 }
+
+export interface IMetadataKey {
+       name:string;
+       mandatory:boolean
+       validValues: string[];
+}
index 8a4b257..186cd8a 100644 (file)
@@ -21,6 +21,7 @@
 import { CapabilitiesGroup, RequirementsGroup } from 'app/models';
 import { ComponentType } from 'app/utils';
 import { IMainCategory } from './category';
+import { Metadata } from "app/models/metadata";
 /**
  * Created by obarda on 4/18/2017.
  */
@@ -53,6 +54,7 @@ export interface IComponentMetadata {
     vspArchived: boolean;
     selectedCategory: string;
     filterTerm: string;
+    categorySpecificMetadata: Metadata;
 
     // Resource only
     resourceType: string;
@@ -115,6 +117,7 @@ export class ComponentMetadata implements IComponentMetadata {
     public toscaResourceName: string;
     public selectedCategory: string;
     public filterTerm: string;
+    public categorySpecificMetadata: Metadata = new Metadata();
 
     // Resource only
     public resourceType: string;
@@ -192,6 +195,7 @@ export class ComponentMetadata implements IComponentMetadata {
         this.toscaResourceName = response.toscaResourceName;
         this.capabilities = response.capabilities;
         this.requirements = response.requirements;
+        this.categorySpecificMetadata = response.categorySpecificMetadata;
         return this;
     }
 
index a0706b4..1d48151 100644 (file)
@@ -35,6 +35,7 @@ import {Requirement} from "../requirement";
 import {Relationship} from "../graph/relationship";
 import { PolicyInstance } from "app/models/graph/zones/policy-instance";
 import { GroupInstance } from "../graph/zones/group-instance";
+import { Metadata } from "app/models/metadata";
 
 
 // import {}
@@ -142,6 +143,7 @@ export abstract class Component implements IComponent {
     public archived:boolean;
     public vspArchived: boolean;
     public componentMetadata: ComponentMetadata;
+    public categorySpecificMetadata: Metadata = new Metadata();
 
     constructor(componentService:IComponentService, protected $q:ng.IQService, component?:Component) {
         if (component) {
@@ -198,12 +200,36 @@ export abstract class Component implements IComponent {
             this.policies = component.policies;
             this.archived = component.archived;
             this.vspArchived = component.vspArchived;
+
+            if (component.categorySpecificMetadata && component.categories && component.categories[0]){
+                this.copyCategoryMetadata(component);
+                this.copySubcategoryMetadata(component);
+            }
         }
 
         //custom properties
         this.componentService = componentService;
     }
 
+    private copyCategoryMetadata = (component:Component):void => {
+        if (component.categories[0].metadataKeys){
+            for (let key of Object.keys(component.categorySpecificMetadata)) {
+                if (component.categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
+                    this.categorySpecificMetadata[key] = component.categorySpecificMetadata[key];
+                }
+            }
+        }
+    }
+    private copySubcategoryMetadata = (component:Component):void => {
+        if (component.categories[0].subcategories && component.categories[0].subcategories[0] && component.categories[0].subcategories[0].metadataKeys){
+            for (let key of Object.keys(component.categorySpecificMetadata)) {
+                if (component.categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
+                    this.categorySpecificMetadata[key] = component.categorySpecificMetadata[key];
+                }
+            }
+        }
+    }
+
     public setUniqueId = (uniqueId:string):void => {
         this.uniqueId = uniqueId;
     };
@@ -543,6 +569,11 @@ export abstract class Component implements IComponent {
         this.archived = componentMetadata.archived || false;
         this.vspArchived = componentMetadata.vspArchived;
         this.componentMetadata = componentMetadata;
+        if (componentMetadata.categorySpecificMetadata){
+            this.categorySpecificMetadata = componentMetadata.categorySpecificMetadata;
+        } else {
+            this.categorySpecificMetadata = new Metadata();
+        }
     }
 
     public toJSON = ():any => {
index 71545f8..cafe93e 100644 (file)
             <span class="value" data-tests-id="rightTab_customizationModuleUUID" tooltip="{{component.customizationUUID}}">{{component.customizationUUID}}</span>
         </div>
 
+        <!-- Category specific metadata -->
+        <ng-container *ngFor="let metadata of component.categorySpecificMetadata | keyValue">
+            <div class="component-details-panel-item">
+                <span class="name" innerHTML="{{metadata.key}}"></span>
+                <span class="value" tooltip="{{metadata.value}}">{{metadata.value}}</span>
+            </div>
+        </ng-container>
+
         <!-- DESCRIPTION -->
         <div class="component-details-panel-item description">
             <span class="name" [innerHTML]="'GENERAL_LABEL_DESCRIPTION' | translate"></span>
index 6915d65..388e4b5 100644 (file)
@@ -19,6 +19,8 @@ import _ from "lodash";
 import { TranslateService } from "../../../../../shared/translator/translate.service";
 import { SdcUiServices } from "onap-ui-angular";
 import { Component as TopologyTemplate, FullComponentInstance, ComponentInstance } from '../../../../../../../app/models';
+import {KeyValuePipe} from "../../../../../pipes/key-value.pipe";
+
 
 
 describe('InfoTabComponent', () => {
@@ -48,7 +50,7 @@ describe('InfoTabComponent', () => {
             const configure: ConfigureFn = testBed => {
                 testBed.configureTestingModule({
                     imports: [ ],
-                    declarations: [ InfoTabComponent, TranslatePipe ],
+                    declarations: [ InfoTabComponent, TranslatePipe, KeyValuePipe ],
                     schemas: [ NO_ERRORS_SCHEMA ],
                     providers: [
                         { provide: Store, useValue: {} },
index e10dc98..cab4b6c 100644 (file)
@@ -24,12 +24,13 @@ import {ModalsHandler, ValidationUtils, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FL
     ResourceType, ComponentState, instantiationType, ComponentFactory} from "app/utils";
 import { EventListenerService, ProgressService} from "app/services";
 import {CacheService, OnboardingService, ImportVSPService} from "app/services-ng2";
-import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component} from "app/models";
+import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component, IMetadataKey} from "app/models";
 import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
 import {Dictionary} from "lodash";
 import { PREVIOUS_CSAR_COMPONENT } from "../../../../utils/constants";
 import { Observable, Subject } from "rxjs";
-
+import { MetadataEntry } from "app/models/metadataEntry";
+import { Metadata } from "app/models/metadata";
 
 export class Validation {
     componentNameValidationPattern:RegExp;
@@ -630,6 +631,20 @@ export class GeneralViewModel {
             this.$scope.component.selectedCategory = this.$scope.componentCategories.selectedCategory;
             this.$scope.component.categories = this.convertCategoryStringToOneArray();
             this.$scope.component.icon = DEFAULT_ICON;
+            if (this.$scope.component.categories[0].metadataKeys) {
+                for (let metadataKey of this.$scope.component.categories[0].metadataKeys) {
+                    if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
+                        this.$scope.component.categorySpecificMetadata[metadataKey.name] = "";
+                   }
+                }
+            }
+            if (this.$scope.component.categories[0].subcategories && this.$scope.component.categories[0].subcategories[0].metadataKeys) {
+                for (let metadataKey of this.$scope.component.categories[0].subcategories[0].metadataKeys) {
+                    if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) {
+                        this.$scope.component.categorySpecificMetadata[metadataKey.name] = "";
+                   }
+                }
+            }
         };
 
         this.$scope.onEcompGeneratedNamingChange = (): void => {
@@ -645,11 +660,51 @@ export class GeneralViewModel {
         };
         this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload);
 
+
+        this.$scope.isMetadataKeyMandatory = (key: string): boolean => {
+            let metadataKey = this.getMetadataKey(this.$scope.component.categories, key);
+            return metadataKey && metadataKey.mandatory;
+        }
+
+        this.$scope.getMetadataKeyValidValues = (key: string): string[] => {
+            let metadataKey = this.getMetadataKey(this.$scope.component.categories, key);
+            if (metadataKey) {
+                return metadataKey.validValues;
+            }
+            return []; 
+        }
+
+        this.$scope.isMetadataKeyForComponentCategory = (key: string): boolean => {
+            return this.getMetadataKey(this.$scope.component.categories, key) != null;
+        }
+
     }
 
     private setUnsavedChanges = (hasChanges: boolean): void => {
         this.$state.current.data.unsavedChanges = hasChanges;
     }
 
+    private getMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
+        let metadataKey = this.getSubcategoryMetadataKey(this.$scope.component.categories, key);
+        if (!metadataKey){
+            return this.getCategoryMetadataKey(this.$scope.component.categories, key);
+        }
+        return metadataKey;
+    }
+
+    private getSubcategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
+           if (categories[0].subcategories && categories[0].subcategories[0].metadataKeys && categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
+            return categories[0].subcategories[0].metadataKeys.find(metadataKey => metadataKey.name == key);
+        }
+        return null;
+    }
+
+    private getCategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey {
+           if (categories[0].metadataKeys && categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
+            return categories[0].metadataKeys.find(metadataKey => metadataKey.name == key);
+        }
+        return null;
+    }
+
 }
 
index 42a8aa3..a04948e 100644 (file)
                             <!--------------------- CATEGORIES -------------------->
                         </div>
                     </div>
+
+                    <!--------------------- Category Specific Metadata -------------------->
+
+                    <div ng-if="component.selectedCategory">
+                        <ng-container ng-repeat="(key, value) in component.categorySpecificMetadata"-->
+                            <div ng-if="isMetadataKeyForComponentCategory(key) && getMetadataKeyValidValues(key) && isMetadataKeyMandatory(key)"
+                                 class="i-sdc-form-item"
+                                 data-ng-class="{'error': validateField(editForm['{{key}}'])}">
+                                <label class="i-sdc-form-label required" translate="{{key}}"></label>
+                                <select class="i-sdc-form-select"
+                                    name="{{key}}"
+                                    data-ng-class="{'view-mode': isViewMode()}"
+                                    data-ng-model="component.categorySpecificMetadata[key]"
+                                    data-tests-id="{{key}}"
+                                    data-required>
+                                   <option ng-repeat="value in getMetadataKeyValidValues(key)">{{value}}</option>
+                                </select>
+                                <div class="input-error" data-ng-show="validateField(editForm['{{key}}'])">
+                                    <span ng-show="editForm['{{key}}'].$error.required" translate="NEW_SERVICE_RESOURCE_ERROR_REQUIRED"></span>
+                                </div>
+                            </div>
+                            <div ng-if="isMetadataKeyForComponentCategory(key) && getMetadataKeyValidValues(key) && !isMetadataKeyMandatory(key)"
+                                 class="i-sdc-form-item">
+                                <label class="i-sdc-form-label" translate="{{key}}"></label>
+                                <select class="i-sdc-form-select"
+                                    name="{{key}}"
+                                    data-ng-class="{'view-mode': isViewMode()}"
+                                    data-ng-model="component.categorySpecificMetadata[key]"
+                                    data-tests-id="{{key}}">
+                                   <option ng-repeat="value in getMetadataKeyValidValues(key)">{{value}}</option>
+                                </select>
+                            </div>
+                            <div ng-if="isMetadataKeyForComponentCategory(key) && !getMetadataKeyValidValues(key) && isMetadataKeyMandatory(key)"
+                                 class="i-sdc-form-item"
+                                 data-ng-class="{'error': validateField(editForm['{{key}}'])}">
+                                <label class="i-sdc-form-label required" translate="{{key}}"></label>
+                                <input class="i-sdc-form-input" type="text"
+                                       data-required
+                                       data-ng-class="{'view-mode': isViewMode()}"
+                                       data-ng-model="component.categorySpecificMetadata[key]"
+                                       name="{{key}}"
+                                       data-tests-id="{{key}}"
+                                />
+                                <div class="input-error" data-ng-show="validateField(editForm['{{key}}'])">
+                                    <span ng-show="editForm['{{key}}'].$error.required" translate="NEW_SERVICE_RESOURCE_ERROR_REQUIRED"></span>
+                                </div>
+                            </div>
+                            <div ng-if="isMetadataKeyForComponentCategory(key) && !getMetadataKeyValidValues(key) && !isMetadataKeyMandatory(key)"
+                                 class="i-sdc-form-item">
+                                <label class="i-sdc-form-label" translate="{{key}}"></label>
+                                <input class="i-sdc-form-input" type="text"
+                                       data-ng-class="{'view-mode': isViewMode()}"
+                                       data-ng-model="component.categorySpecificMetadata[key]"
+                                       name="{{key}}"
+                                       data-tests-id="{{key}}"
+                                />
+                            </div>
+                        </ng-container>
+                    </div>
                 <!--------------------- RESOURCE TAGS -------------------->
                 <div class="i-sdc-form-item" data-ng-class="{'error': validateField(editForm.tags)}">
                     <label class="i-sdc-form-label" translate="GENERAL_LABEL_TAGS"></label>
index cad8fc7..fd4a382 100644 (file)
     "NEW_SERVICE_RESOURCE_ERROR_RESOURCE_DESCRIPTION_REQUIRED": "Description is required.",
     "NEW_SERVICE_RESOURCE_ERROR_VENDOR_NAME_REQUIRED": "Vendor name is required.",
     "NEW_SERVICE_RESOURCE_ERROR_VENDOR_RELEASE_REQUIRED": "Vendor Release is required.",
+    "NEW_SERVICE_RESOURCE_ERROR_REQUIRED": "Value is required.",
     "NEW_SERVICE_RESOURCE_ERROR_TEMPLATE_REQUIRED": "Template is required.",
     "NEW_SERVICE_RESOURCE_ERROR_TAG_PATTERN": "{{text}}",
     "NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS_TITLE": "Invalid Tosca file",
index cf0117f..5758dbe 100644 (file)
@@ -40,6 +40,7 @@ public class CategoryDataDefinition extends ToscaDataDefinition {
     private String uniqueId;
     private List<String> icons;
     private boolean useServiceSubstitutionForNestedServices = false;
+    private List<MetadataKeyDataDefinition> metadataKeys;
 
     public CategoryDataDefinition(CategoryDataDefinition c) {
         this.name = c.name;
@@ -47,6 +48,7 @@ public class CategoryDataDefinition extends ToscaDataDefinition {
         this.uniqueId = c.uniqueId;
         this.icons = c.icons;
         this.useServiceSubstitutionForNestedServices = c.useServiceSubstitutionForNestedServices;
+        this.metadataKeys = c.metadataKeys;
     }
 
 }
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/MetadataKeyDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/category/MetadataKeyDataDefinition.java
new file mode 100644 (file)
index 0000000..4d8a197
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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=========================================================
+ */
+package org.openecomp.sdc.be.datatypes.category;
+
+import java.util.List;
+import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@ToString
+@NoArgsConstructor
+public class MetadataKeyDataDefinition extends ToscaDataDefinition {
+    private String name;
+    private List<String> validValues;
+    private boolean mandatory;
+    
+    public MetadataKeyDataDefinition(MetadataKeyDataDefinition metadataKeyDataDefinition) {
+        this.name = metadataKeyDataDefinition.name;
+        this.validValues = metadataKeyDataDefinition.validValues;
+        this.mandatory = metadataKeyDataDefinition.mandatory;
+    }
+}
index 986f79f..38d7027 100644 (file)
 package org.openecomp.sdc.be.datatypes.category;
 
 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
-
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
 import java.util.List;
 
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+@ToString
+@NoArgsConstructor
 public class SubCategoryDataDefinition extends ToscaDataDefinition {
 
     private String name;
     private String normalizedName;
     private String uniqueId;
     private List<String> icons;
-
-    public SubCategoryDataDefinition() {
-
-    }
+    private List<MetadataKeyDataDefinition> metadataKeys;
 
     public SubCategoryDataDefinition(SubCategoryDataDefinition c) {
         this.name = c.name;
         this.normalizedName = c.normalizedName;
         this.uniqueId = c.uniqueId;
         this.icons = c.icons;
+        this.metadataKeys = c.metadataKeys;
     }
 
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getNormalizedName() {
-        return normalizedName;
-    }
-
-    public void setNormalizedName(String normalizedName) {
-        this.normalizedName = normalizedName;
-    }
-
-    public String getUniqueId() {
-        return uniqueId;
-    }
-
-    public void setUniqueId(String uniqueId) {
-        this.uniqueId = uniqueId;
-    }
-
-    public List<String> getIcons() {
-        return icons;
-    }
-
-    public void setIcons(List<String> icons) {
-        this.icons = icons;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((name == null) ? 0 : name.hashCode());
-        result = prime * result + ((normalizedName == null) ? 0 : normalizedName.hashCode());
-        result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode());
-        result = prime * result + ((icons == null) ? 0 : icons.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        SubCategoryDataDefinition other = (SubCategoryDataDefinition) obj;
-        if (name == null) {
-            if (other.name != null) {
-                return false;
-            }
-        } else if (!name.equals(other.name)) {
-            return false;
-        }
-        if (normalizedName == null) {
-            if (other.normalizedName != null) {
-                return false;
-            }
-        } else if (!normalizedName.equals(other.normalizedName)) {
-            return false;
-        }
-        if (uniqueId == null) {
-            if (other.uniqueId != null) {
-                return false;
-            }
-        } else if (!uniqueId.equals(other.uniqueId)) {
-            return false;
-        }
-        if (icons == null) {
-            return other.icons == null;
-        } else {
-            return icons.equals(other.icons);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "SubCategoryDataDefinition [name=" + name + ", normalizedName=" + normalizedName + ", uniqueId="
-                + uniqueId + ", icons=" + icons + "]";
-    }
 }
index e1d0d96..96cccf6 100644 (file)
@@ -131,6 +131,9 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio
     @Getter
     @Setter
     private Boolean isVspArchived = false;
+    @Getter
+    @Setter
+    private Map<String, String> categorySpecificMetadata;
 
     public ComponentMetadataDataDefinition(ComponentMetadataDataDefinition other) {
         this.uniqueId = other.getUniqueId();
@@ -157,6 +160,7 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio
         this.isArchived = other.isArchived;
         this.isVspArchived = other.isVspArchived;
         this.archiveTime = other.getArchiveTime();
+        this.categorySpecificMetadata = other.getCategorySpecificMetadata();
     }
 
     public ComponentMetadataDataDefinition(JsonPresentationFieldsExtractor extractor) {
@@ -245,4 +249,5 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio
      * @return
      */
     public abstract String getActualComponentType();
+
 }
index 70f7603..44a0d23 100644 (file)
@@ -54,6 +54,7 @@ public enum GraphPropertyEnum {
     LAST_LOGIN_TIME("lastLoginTime", Long.class, false, false),
     //used for category (old format, no json for categories)
     ICONS("icons", String.class, false, false),
+    METADATA_KEYS("metadataKeys", String.class, false, false),
     USE_SUBSTITUTION_FOR_NESTED_SERVICES("useServiceSubstitutionForNestedServices", Boolean.class, false, false),
 
     DATA_TYPES("data_types", Map.class, false, false),
index 436f958..34382df 100644 (file)
@@ -48,6 +48,10 @@ public enum JsonPresentationFields {
     DERIVED_FROM("derivedFrom", null),
     VENDOR_NAME("vendorName", null),
     VENDOR_RELEASE("vendorRelease", null),
+    CATEGORY("category", null),
+    SUB_CATEGORY("subcategory", null),
+    RESOURCE_VENDOR("resourceVendor", null),
+    RESOURCE_VENDOR_RELEASE("resourceVendorRelease", null),
     RESOURCE_VENDOR_MODEL_NUMBER("reourceVendorModelNumber", null),
     SERVICE_TYPE("serviceType", null),
     SERVICE_ROLE("serviceRole", null),
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/MetadataKeyEnum.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/MetadataKeyEnum.java
new file mode 100644 (file)
index 0000000..0ed8eab
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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=========================================================
+ */
+package org.openecomp.sdc.be.datatypes.enums;
+
+import lombok.Getter;
+
+public enum MetadataKeyEnum {
+    METADATA_KEYS("metadataKeys"), 
+    NAME("name"), 
+    MANDATORY("mandatory"),
+    VALID_VALUES("validValues");
+
+    @Getter
+    private final String name;
+
+    MetadataKeyEnum(final String name) {
+        this.name = name;
+    }
+
+}