aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrupaNagabhushan <krupa.nagabhushan@est.tech>2022-07-05 18:43:07 +0100
committerKrupa Nagabhushan <krupa.nagabhushan@est.tech>2022-08-02 21:10:26 +0000
commit7c7680d767bce8625c9c7ad69009fb73ae849809 (patch)
treefc3cb8f1482ac8c6dfcb22feb085757ea180cfa0
parenta9d0bcd206b7a677b82e5e9b497a8b52b38e3a43 (diff)
Service Import - Node Template Relationship Template
Issue-ID: SDC-4083 Signed-off-by: KrupaNagabhushan <krupa.nagabhushan@est.tech> Signed-off-by: andre.schmid <andre.schmid@est.tech> Change-Id: Ia0f3635df969c44de5aba2d672fad34f0855e4e2
-rw-r--r--catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml14
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java135
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java15
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandlerTest.java29
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java2
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBussinessLogicBaseTestSetup.java12
-rw-r--r--catalog-be/src/test/resources/csars/with_groups.csarbin66267 -> 66821 bytes
-rw-r--r--catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java3
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadComponentInstanceInfo.java2
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadReqInfo.java23
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java1
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java47
-rw-r--r--catalog-model/src/test/java/org/openecomp/sdc/be/model/UploadReqInfoTest.java33
-rw-r--r--catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverterTest.java48
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/utils/TypeUtils.java5
15 files changed, 307 insertions, 62 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
index 58f3dc337c..50a7014f10 100644
--- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
+++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
@@ -2732,3 +2732,17 @@ errors:
message: "Missing TOSCA function '%1'.",
messageId: "SVC4172"
}
+
+ #-----------SVC4173---------------------------
+ RELATIONSHIP_TEMPLATE_NOT_FOUND: {
+ code: 404,
+ message: "Relationship_templates entry not found in TOSCA CSAR.",
+ messageId: "SVC4173"
+ }
+
+ #-----------SVC4174---------------------------
+ RELATIONSHIP_TEMPLATE_DEFINITION_NOT_FOUND: {
+ code: 404,
+ message: "Relationship_templates definition not found in TOSCA CSAR.",
+ messageId: "SVC4174"
+ }
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java
index 940363bce4..a68bbf3a2d 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java
@@ -29,6 +29,8 @@ import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaLis
import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaMapElement;
import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement;
import static org.openecomp.sdc.be.components.impl.ImportUtils.loadYamlAsStrictMap;
+import static org.openecomp.sdc.be.datatypes.enums.MetadataKeyEnum.NAME;
+import static org.openecomp.sdc.be.model.tosca.ToscaType.STRING;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ARTIFACTS;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ATTRIBUTES;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.CAPABILITIES;
@@ -38,15 +40,20 @@ import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.FILE;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.GET_INPUT;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.GROUPS;
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.IMPLEMENTATION;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS;
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INTERFACES;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.IS_PASSWORD;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.MEMBERS;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NODE;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NODE_TYPE;
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OUTPUTS;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.POLICIES;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.PROPERTIES;
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.RELATIONSHIP;
+import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.RELATIONSHIP_TEMPLATES;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIREMENTS;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.SUBSTITUTION_FILTERS;
import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.SUBSTITUTION_MAPPINGS;
@@ -66,7 +73,9 @@ import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -108,6 +117,9 @@ import org.openecomp.sdc.be.model.UploadComponentInstanceInfo;
import org.openecomp.sdc.be.model.UploadPropInfo;
import org.openecomp.sdc.be.model.UploadReqInfo;
import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
+import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
+import org.openecomp.sdc.be.ui.model.OperationUi;
+import org.openecomp.sdc.be.ui.model.PropertyAssignmentUi;
import org.openecomp.sdc.be.utils.TypeUtils;
import org.openecomp.sdc.common.log.wrappers.Logger;
import org.yaml.snakeyaml.parser.ParserException;
@@ -140,9 +152,9 @@ public class YamlTemplateParsingHandler {
Map<String, NodeTypeInfo> nodeTypesInfo, String nodeName,
Component component, String interfaceTemplateYaml) {
log.debug("#parseResourceInfoFromYAML - Going to parse yaml {} ", fileName);
- final Map<String, Object> mappedToscaTemplate = getMappedToscaTemplate(fileName, resourceYml, nodeTypesInfo, nodeName);
- final ParsedToscaYamlInfo parsedToscaYamlInfo = new ParsedToscaYamlInfo();
- final Map<String, Object> mappedTopologyTemplate = (Map<String, Object>) findToscaElement(mappedToscaTemplate, TOPOLOGY_TEMPLATE,
+ Map<String, Object> mappedToscaTemplate = getMappedToscaTemplate(fileName, resourceYml, nodeTypesInfo, nodeName);
+ ParsedToscaYamlInfo parsedToscaYamlInfo = new ParsedToscaYamlInfo();
+ Map<String, Object> mappedTopologyTemplate = (Map<String, Object>) findToscaElement(mappedToscaTemplate, TOPOLOGY_TEMPLATE,
ToscaElementTypeEnum.ALL).left().on(err -> failIfNotTopologyTemplate(fileName));
final Map<String, Object> mappedTopologyTemplateInputs = mappedTopologyTemplate.entrySet().stream()
.filter(entry -> entry.getKey().equals(INPUTS.getElementName())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
@@ -151,6 +163,7 @@ public class YamlTemplateParsingHandler {
parsedToscaYamlInfo.setInputs(getInputs(mappedTopologyTemplateInputs));
parsedToscaYamlInfo.setOutputs(getOutputs(mappedTopologyTemplateOutputs));
parsedToscaYamlInfo.setInstances(getInstances(mappedToscaTemplate, createdNodesToscaResourceNames));
+ associateRelationshipTemplatesToInstances(parsedToscaYamlInfo.getInstances(), mappedTopologyTemplate);
parsedToscaYamlInfo.setGroups(getGroups(mappedToscaTemplate, component.getModel()));
parsedToscaYamlInfo.setPolicies(getPolicies(mappedToscaTemplate, component.getModel()));
Map<String, Object> substitutionMappings = getSubstitutionMappings(mappedToscaTemplate);
@@ -354,6 +367,102 @@ public class YamlTemplateParsingHandler {
return null;
}
+ private void associateRelationshipTemplatesToInstances(final Map<String, UploadComponentInstanceInfo> instances,
+ final Map<String, Object> toscaJson) {
+ if (MapUtils.isEmpty(instances)) {
+ return;
+ }
+ for (UploadComponentInstanceInfo instance : instances.values()) {
+ final Map<String, List<OperationUi>> operations = new HashMap<>();
+ final Map<String, List<UploadReqInfo>> requirements = instance.getRequirements();
+ if (MapUtils.isNotEmpty(requirements)) {
+ requirements.values()
+ .forEach(requirementInfoList -> requirementInfoList.stream()
+ .filter(requirement -> StringUtils.isNotEmpty(requirement.getRelationshipTemplate()))
+ .forEach(requirement -> operations.put(requirement.getRelationshipTemplate(),
+ getOperationsFromRelationshipTemplate(toscaJson, requirement.getRelationshipTemplate()))));
+ }
+ instance.setOperations(operations);
+ }
+ }
+
+ private Map<String, Object> getRelationshipTemplates(final Map<String, Object> toscaJson, final String relationshipTemplate) {
+ final Either<Map<String, Object>, ResultStatusEnum> eitherRelationshipTemplates = findFirstToscaMapElement(toscaJson, RELATIONSHIP_TEMPLATES);
+ if (eitherRelationshipTemplates.isRight()) {
+ throw new ByActionStatusComponentException(ActionStatus.RELATIONSHIP_TEMPLATE_NOT_FOUND);
+ }
+ final Map<String, Object> relationshipTemplateMap = eitherRelationshipTemplates.left().value();
+ final Map<String, Map<String, Object>> relationship = (Map<String, Map<String, Object>>) relationshipTemplateMap.get(relationshipTemplate);
+ if (relationship == null) {
+ throw new ByActionStatusComponentException(ActionStatus.RELATIONSHIP_TEMPLATE_DEFINITION_NOT_FOUND);
+ }
+ return relationship.get(INTERFACES.getElementName());
+ }
+
+ private List<ToscaInterfaceDefinition> buildToscaInterfacesFromRelationship(final Map<String, Object> interfaces) {
+ return interfaces.entrySet().stream()
+ .map(entry -> {
+ final var toscaInterfaceDefinition = new ToscaInterfaceDefinition();
+ toscaInterfaceDefinition.setType(entry.getKey());
+ final Map<String, Object> toscaInterfaceMap = (Map<String, Object>) entry.getValue();
+ toscaInterfaceDefinition.setOperations((Map<String, Object>) toscaInterfaceMap.get(OPERATIONS.getElementName()));
+ return toscaInterfaceDefinition;
+ })
+ .collect(toList());
+ }
+
+ private Optional<Object> getImplementation(final Map<String, Object> operationToscaMap) {
+ if (MapUtils.isEmpty(operationToscaMap) || !operationToscaMap.containsKey(IMPLEMENTATION.getElementName())) {
+ return Optional.empty();
+ }
+ final Map<String, Object> implementationToscaMap = (Map<String, Object>) operationToscaMap.get(IMPLEMENTATION.getElementName());
+ return Optional.ofNullable(
+ implementationToscaMap.computeIfPresent("toscaPresentation", (key, value) -> ((Map<String, Object>) value).get(NAME.getName()))
+ );
+ }
+
+ private List<PropertyAssignmentUi> getOperationsInputs(final Map<String, Object> operationToscaMap) {
+ if (MapUtils.isEmpty(operationToscaMap) || !operationToscaMap.containsKey(INPUTS.getElementName())) {
+ return Collections.emptyList();
+ }
+ final Map<String, Object> inputsMap = (Map<String, Object>) operationToscaMap.get(INPUTS.getElementName());
+ return inputsMap.entrySet().stream().map(this::buildInputAssignment).collect(toList());
+ }
+
+ private PropertyAssignmentUi buildInputAssignment(final Entry<String, Object> inputAssignmentMap) {
+ var propertyAssignmentUi = new PropertyAssignmentUi();
+ propertyAssignmentUi.setName(inputAssignmentMap.getKey());
+ propertyAssignmentUi.setValue(inputAssignmentMap.getValue().toString());
+ propertyAssignmentUi.setType(STRING.getType());
+ return propertyAssignmentUi;
+ }
+
+ private List<OperationUi> getOperationsFromRelationshipTemplate(final Map<String, Object> toscaJson, final String relationshipTemplate) {
+ final List<OperationUi> operationUiList = new ArrayList<>();
+ final List<ToscaInterfaceDefinition> interfaces =
+ buildToscaInterfacesFromRelationship(getRelationshipTemplates(toscaJson, relationshipTemplate));
+ interfaces.stream()
+ .filter(interfaceDefinition -> MapUtils.isNotEmpty(interfaceDefinition.getOperations()))
+ .forEach(interfaceDefinition ->
+ interfaceDefinition.getOperations()
+ .forEach((operationType, operationValue) ->
+ operationUiList.add(buildOperation(interfaceDefinition.getType(), operationType, (Map<String, Object>) operationValue))
+ ));
+ return operationUiList;
+ }
+
+ private OperationUi buildOperation(final String interfaceType, final String operationType, final Map<String, Object> operationToscaMap) {
+ var operationUi = new OperationUi();
+ operationUi.setInterfaceType(interfaceType);
+ operationUi.setOperationType(operationType);
+ getImplementation(operationToscaMap).ifPresent(operationUi::setImplementation);
+ final List<PropertyAssignmentUi> operationsInputs = getOperationsInputs(operationToscaMap);
+ if (CollectionUtils.isNotEmpty(operationsInputs)) {
+ operationUi.setInputs(operationsInputs);
+ }
+ return operationUi;
+ }
+
@SuppressWarnings("unchecked")
private Map<String, GroupDefinition> getGroups(Map<String, Object> toscaJson, String model) {
Map<String, Object> mappedTopologyTemplate = (Map<String, Object>) findToscaElement(toscaJson, TOPOLOGY_TEMPLATE, ToscaElementTypeEnum.ALL)
@@ -715,7 +824,7 @@ public class YamlTemplateParsingHandler {
private void setRequirements(UploadComponentInstanceInfo nodeTemplateInfo, Map<String, Object> nodeTemplateJsonMap) {
if (nodeTemplateJsonMap.containsKey(REQUIREMENTS.getElementName())) {
- Map<String, List<UploadReqInfo>> regResponse = createReqModuleFromYaml(nodeTemplateJsonMap);
+ Map<String, List<UploadReqInfo>> regResponse = createReqModuleFromYaml(nodeTemplateJsonMap, nodeTemplateInfo.getName());
if (!regResponse.isEmpty()) {
nodeTemplateInfo.setRequirements(regResponse);
}
@@ -746,14 +855,14 @@ public class YamlTemplateParsingHandler {
}
@SuppressWarnings("unchecked")
- private Map<String, List<UploadReqInfo>> createReqModuleFromYaml(Map<String, Object> nodeTemplateJsonMap) {
+ private Map<String, List<UploadReqInfo>> createReqModuleFromYaml(Map<String, Object> nodeTemplateJsonMap, String nodeName) {
Map<String, List<UploadReqInfo>> moduleRequirements = new HashMap<>();
Either<List<Object>, ResultStatusEnum> requirementsListRes = findFirstToscaListElement(nodeTemplateJsonMap, REQUIREMENTS);
if (requirementsListRes.isLeft()) {
for (Object jsonReqObj : requirementsListRes.left().value()) {
String reqName = ((Map<String, Object>) jsonReqObj).keySet().iterator().next();
Object reqJson = ((Map<String, Object>) jsonReqObj).get(reqName);
- addModuleNodeTemplateReq(moduleRequirements, reqJson, reqName);
+ addModuleNodeTemplateReq(moduleRequirements, reqJson, reqName, nodeName);
}
} else {
Either<Map<String, Object>, ResultStatusEnum> requirementsMapRes = findFirstToscaMapElement(nodeTemplateJsonMap, REQUIREMENTS);
@@ -761,15 +870,15 @@ public class YamlTemplateParsingHandler {
for (Map.Entry<String, Object> entry : requirementsMapRes.left().value().entrySet()) {
String reqName = entry.getKey();
Object reqJson = entry.getValue();
- addModuleNodeTemplateReq(moduleRequirements, reqJson, reqName);
+ addModuleNodeTemplateReq(moduleRequirements, reqJson, reqName, nodeName);
}
}
}
return moduleRequirements;
}
- private void addModuleNodeTemplateReq(Map<String, List<UploadReqInfo>> moduleRequirements, Object requirementJson, String requirementName) {
- UploadReqInfo requirement = buildModuleNodeTemplateReg(requirementJson);
+ private void addModuleNodeTemplateReq(Map<String, List<UploadReqInfo>> moduleRequirements, Object requirementJson, String requirementName, String nodeName) {
+ UploadReqInfo requirement = buildModuleNodeTemplateReg(requirementJson, nodeName);
requirement.setName(requirementName);
if (moduleRequirements.containsKey(requirementName)) {
moduleRequirements.get(requirementName).add(requirement);
@@ -911,7 +1020,7 @@ public class YamlTemplateParsingHandler {
}
@SuppressWarnings("unchecked")
- private UploadReqInfo buildModuleNodeTemplateReg(Object regObject) {
+ private UploadReqInfo buildModuleNodeTemplateReg(Object regObject, String nodeName) {
UploadReqInfo regTemplateInfo = new UploadReqInfo();
if (regObject instanceof String) {
String nodeTemplateJsonString = (String) regObject;
@@ -924,6 +1033,12 @@ public class YamlTemplateParsingHandler {
if (nodeTemplateJsonMap.containsKey(CAPABILITY.getElementName())) {
regTemplateInfo.setCapabilityName((String) nodeTemplateJsonMap.get(CAPABILITY.getElementName()));
}
+ if (nodeTemplateJsonMap.containsKey(RELATIONSHIP.getElementName())) {
+ final String template = (String) nodeTemplateJsonMap.get(RELATIONSHIP.getElementName());
+ if (StringUtils.isNotEmpty(nodeName) && template.contains(nodeName)) {
+ regTemplateInfo.setRelationshipTemplate(template);
+ }
+ }
}
return regTemplateInfo;
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java
index 225a6c4408..0850535108 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java
@@ -40,6 +40,7 @@ import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.openecomp.sdc.be.components.csar.CsarArtifactsAndGroupsBusinessLogic;
import org.openecomp.sdc.be.components.csar.CsarBusinessLogic;
@@ -132,6 +133,7 @@ import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
import org.openecomp.sdc.be.tosca.CsarUtils;
+import org.openecomp.sdc.be.ui.model.OperationUi;
import org.openecomp.sdc.be.utils.TypeUtils;
import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
import org.openecomp.sdc.common.api.ArtifactTypeEnum;
@@ -1862,6 +1864,9 @@ public class ServiceImportBusinessLogic {
reqAndRelationshipPair.setCapabilityOwnerId(aviableCapForRel.getOwnerId());
CapabilityRequirementRelationship capReqRel = new CapabilityRequirementRelationship();
capReqRel.setRelation(reqAndRelationshipPair);
+ if (StringUtils.isNotEmpty(uploadRegInfo.getRelationshipTemplate())) {
+ capReqRel.setOperations(getOperations(nodesInfoValue.getOperations(), uploadRegInfo.getRelationshipTemplate()));
+ }
reqAndRelationshipPairList.add(capReqRel);
regCapRelDef.setRelationships(reqAndRelationshipPairList);
relations.add(regCapRelDef);
@@ -1871,6 +1876,16 @@ public class ServiceImportBusinessLogic {
return componentsUtils.getResponseFormat(ActionStatus.OK, yamlName);
}
+ private List<OperationUi> getOperations(final Map<String, List<OperationUi>> operations, final String relationshipTemplate) {
+ final List<OperationUi> operationUiList = new ArrayList<>();
+ operations.forEach((operationKey, operationValues) -> {
+ if (operationKey.equals(relationshipTemplate)) {
+ operationUiList.addAll(operationValues);
+ }
+ });
+ return operationUiList;
+ }
+
protected Service getResourceAfterCreateRelations(Service service) {
ComponentParametersView parametersView = serviceImportParseLogic.getComponentFilterAfterCreateRelations();
Either<Service, StorageOperationStatus> eitherGetResource = toscaOperationFacade.getToscaElement(service.getUniqueId(), parametersView);
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandlerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandlerTest.java
index edf17b7e61..6d779a192e 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandlerTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandlerTest.java
@@ -32,6 +32,7 @@ import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ARTIFACTS;
import java.io.File;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -40,6 +41,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import mockit.Deencapsulation;
import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -65,8 +67,10 @@ import org.openecomp.sdc.be.model.Resource;
import org.openecomp.sdc.be.model.Service;
import org.openecomp.sdc.be.model.UploadArtifactInfo;
import org.openecomp.sdc.be.model.UploadComponentInstanceInfo;
+import org.openecomp.sdc.be.model.UploadReqInfo;
import org.openecomp.sdc.be.model.User;
import org.openecomp.sdc.be.model.operations.impl.AnnotationTypeOperations;
+import org.openecomp.sdc.be.ui.model.OperationUi;
import org.openecomp.sdc.common.zip.ZipUtils;
import org.openecomp.sdc.common.zip.exception.ZipException;
import org.springframework.test.util.ReflectionTestUtils;
@@ -175,6 +179,31 @@ public class YamlTemplateParsingHandlerTest {
}
@Test
+ void parseRelationshipTemplateInfoFromYamlTest() {
+ when(groupTypeBusinessLogic.getLatestGroupTypeByType(eq(HEAT_GROUP_TYPE), any())).thenReturn(heatGroupType);
+ String main_template_content = new String(csar.get(MAIN_TEMPLATE_NAME));
+ CsarInfo csarInfo = new CsarInfo(user, CSAR_UUID, csar, RESOURCE_NAME,
+ MAIN_TEMPLATE_NAME, main_template_content, true);
+
+ Service service = new Service();
+ ParsedToscaYamlInfo parsedYaml = handler.parseResourceInfoFromYAML(FILE_NAME, resourceYml, new HashMap<>(),
+ csarInfo.extractTypesInfo(), NODE_NAME, service, getInterfaceTemplateYaml(csarInfo).get());
+
+ assertThat(parsedYaml.getInstances()).isNotNull();
+ final Map<String, List<OperationUi>> operations = new HashMap<>();
+ for (UploadComponentInstanceInfo instance : parsedYaml.getInstances().values()) {
+ final Map<String, List<UploadReqInfo>> requirements = instance.getRequirements();
+ if (MapUtils.isNotEmpty(requirements)) {
+ requirements.values()
+ .forEach(requirementInfoList -> requirementInfoList.stream()
+ .filter(requirement -> StringUtils.isNotEmpty(requirement.getRelationshipTemplate()))
+ .forEach(requirement -> operations.putAll(instance.getOperations())));
+ }
+ }
+ assertEquals(1, operations.size());
+ }
+
+ @Test
void parseResourceInfoFromYAMLTest() {
stubGetGroupType();
stubGetPolicyType();
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java
index dcc0289822..1f45f77f3f 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java
@@ -1571,6 +1571,7 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest
any(ComponentInstance.class), any(UploadReqInfo.class))).thenReturn(capabilityDefinition);
when(componentsUtils.getResponseFormat(any(ActionStatus.class), anyString())).thenReturn(responseFormat);
Assertions.assertNotNull(sIBL.addRelationToRI(yamlName, service, nodesInfoValue, relations));
+ Assertions.assertNotNull(relations.get(0).getRelationships().get(0).getOperations());
}
@Test
@@ -1584,7 +1585,6 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest
List<RequirementCapabilityRelDef> relations = new ArrayList<>();
when(componentsUtils.getResponseFormat(any(ActionStatus.class), anyString())).thenReturn(responseFormat);
Assertions.assertNotNull(sIBL.addRelationToRI(yamlName, service, nodesInfoValue, relations));
-
}
@Test
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBussinessLogicBaseTestSetup.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBussinessLogicBaseTestSetup.java
index beaa695fe4..c8fd87ca3b 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBussinessLogicBaseTestSetup.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBussinessLogicBaseTestSetup.java
@@ -102,6 +102,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade
import org.openecomp.sdc.be.model.operations.api.IElementOperation;
import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation;
+import org.openecomp.sdc.be.ui.model.OperationUi;
import org.openecomp.sdc.be.user.Role;
import org.openecomp.sdc.be.user.UserBusinessLogic;
import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
@@ -433,15 +434,26 @@ public class ServiceImportBussinessLogicBaseTestSetup extends BaseBusinessLogicM
uploadReqInfo.setName("uploadReqInfo");
uploadReqInfo.setNode("zxjTestImportServiceAb");
uploadReqInfo.setCapabilityName("tosca.capabilities.Node");
+ uploadReqInfo.setRelationshipTemplate("ExtCP 0.dependency.1");
uploadReqInfoList.add(uploadReqInfo);
requirements.put("requirements", uploadReqInfoList);
uploadNodeFilterInfo.setName("mme_ipu_vdu.virtualbinding");
uploadComponentInstanceInfo.setCapabilities(getCapabilities());
uploadComponentInstanceInfo.setRequirements(requirements);
uploadComponentInstanceInfo.setName("zxjTestImportServiceAb");
+ uploadComponentInstanceInfo.setOperations(getOperations());
return uploadComponentInstanceInfo;
}
+ protected Map<String, List<OperationUi>> getOperations() {
+ String relationshipTemplate = "ExtCP 0.dependency.1";
+ OperationUi operationUi = new OperationUi();
+ operationUi.setOperationType("change_external_connectivity_start");
+ operationUi.setInterfaceType("tosca.interfaces.nfv.Vnflcm");
+ operationUi.setImplementation("impl");
+ return Map.of(relationshipTemplate, List.of(operationUi));
+ }
+
protected Map<String, List<UploadCapInfo>> getCapabilities() {
List<UploadCapInfo> uploadCapInfoList = new ArrayList<>();
UploadCapInfo uploadCapInfo = new UploadCapInfo();
diff --git a/catalog-be/src/test/resources/csars/with_groups.csar b/catalog-be/src/test/resources/csars/with_groups.csar
index dd7f5dfb69..cd701a2078 100644
--- a/catalog-be/src/test/resources/csars/with_groups.csar
+++ b/catalog-be/src/test/resources/csars/with_groups.csar
Binary files differ
diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
index 9c6ac18ef9..603f9ccf61 100644
--- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
+++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
@@ -140,4 +140,7 @@ public enum ActionStatus {
TOSCA_GET_FUNCTION_PROPERTY_NOT_FOUND,
TOSCA_GET_FUNCTION_INSTANCE_NOT_FOUND,
TOSCA_FUNCTION_MISSING_ATTRIBUTE,
+ RELATIONSHIP_TEMPLATE_NOT_FOUND,
+ RELATIONSHIP_TEMPLATE_DEFINITION_NOT_FOUND
+
}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadComponentInstanceInfo.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadComponentInstanceInfo.java
index 57652ee162..ef9f1f17e8 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadComponentInstanceInfo.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadComponentInstanceInfo.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
+import org.openecomp.sdc.be.ui.model.OperationUi;
@Getter
@Setter
@@ -40,4 +41,5 @@ public class UploadComponentInstanceInfo {
private Map<String, String> requirementsNamesToUpdate;
private Collection<String> directives;
private UploadNodeFilterInfo uploadNodeFilterInfo;
+ private Map<String, List<OperationUi>> operations;
}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadReqInfo.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadReqInfo.java
index a3f927925f..b18a8e47a5 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadReqInfo.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/UploadReqInfo.java
@@ -19,6 +19,13 @@
*/
package org.openecomp.sdc.be.model;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
public class UploadReqInfo extends UploadInfo {
/**
@@ -26,20 +33,6 @@ public class UploadReqInfo extends UploadInfo {
*/
private String capabilityName;
private String node;
+ private String relationshipTemplate;
- public String getCapabilityName() {
- return capabilityName;
- }
-
- public void setCapabilityName(String capabilityName) {
- this.capabilityName = capabilityName;
- }
-
- public String getNode() {
- return node;
- }
-
- public void setNode(String node) {
- this.node = node;
- }
}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
index 02fda3c51b..8c08a3d040 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
@@ -2082,6 +2082,7 @@ public class ToscaOperationFacade {
Component updatedComponent = componentEither.left().value();
component.setCapabilities(updatedComponent.getCapabilities());
component.setRequirements(updatedComponent.getRequirements());
+ component.setComponentInstancesRelations(updatedComponent.getComponentInstancesRelations());
component.setComponentInstances(updatedComponent.getComponentInstances());
}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java
index 6dfaebc947..cfc58671e4 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java
@@ -32,6 +32,7 @@ import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
@@ -118,6 +119,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
import org.openecomp.sdc.be.model.jsonjanusgraph.enums.JsonConstantKeysEnum;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeTemplateOperation;
import org.openecomp.sdc.be.model.operations.StorageException;
import org.openecomp.sdc.be.resources.data.ComponentMetadataData;
import org.openecomp.sdc.be.resources.data.ProductMetadataData;
@@ -481,11 +483,56 @@ public class ModelConverter {
requirementCapabilityRelDef.setType(p.getRelation().getRelationship().getType());
requirementCapabilityRelDef.setCapability(p.getRelation().getCapability());
requirementCapabilityRelDef.setOriginUI(relation.isOriginUI());
+ createRelationshipInterfaces(p.getOperations()).ifPresent(requirementCapabilityRelDef::setInterfaces);
relationsList.add(requirementCapabilityRelDef);
});
return relationsList;
}
+ private static Optional<ListDataDefinition<InterfaceDataDefinition>> createRelationshipInterfaces(final List<OperationUi> operationList) {
+ if (CollectionUtils.isEmpty(operationList)) {
+ return Optional.empty();
+ }
+ final ListDataDefinition<InterfaceDataDefinition> interfaceList = new ListDataDefinition<>();
+ final Map<String, List<OperationUi>> operationByInterfaceType = operationList.stream()
+ .collect(Collectors.groupingBy(OperationUi::getInterfaceType));
+ for (final Entry<String, List<OperationUi>> interfaceEntry : operationByInterfaceType.entrySet()) {
+ interfaceList.add(createInterface(interfaceEntry.getKey(), interfaceEntry.getValue()));
+ }
+ return Optional.of(interfaceList);
+ }
+
+ private static InterfaceDataDefinition createInterface(final String interfaceType, final List<OperationUi> operationList) {
+ final InterfaceDataDefinition interfaceDataDefinition = new InterfaceDataDefinition();
+ interfaceDataDefinition.setType(interfaceType);
+ if (CollectionUtils.isNotEmpty(operationList)) {
+ final Map<String, OperationDataDefinition> operationMap = operationList.stream()
+ .collect(Collectors.toMap(OperationUi::getOperationType, ModelConverter::createOperation));
+ interfaceDataDefinition.setOperations(operationMap);
+ }
+ return interfaceDataDefinition;
+ }
+
+ private static OperationDataDefinition createOperation(final OperationUi operation) {
+ final OperationDataDefinition operationDataDefinition = new OperationDataDefinition();
+ operationDataDefinition.setName(operation.getOperationType());
+ operationDataDefinition.setUniqueId(UUID.randomUUID().toString());
+ final ArtifactDataDefinition artifactDataDefinition = (ArtifactDataDefinition) operation.getImplementation();
+ operationDataDefinition.setImplementation(artifactDataDefinition);
+ if (CollectionUtils.isNotEmpty(operation.getInputs())) {
+ final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>();
+ operation.getInputs().forEach(input -> {
+ final OperationInputDefinition operationInputDefinition = new OperationInputDefinition();
+ operationInputDefinition.setLabel(input.getName());
+ operationInputDefinition.setType(input.getType());
+ operationInputDefinition.setValue(input.getValue());
+ inputs.add(operationInputDefinition);
+ });
+ operationDataDefinition.setInputs(inputs);
+ }
+ return operationDataDefinition;
+ }
+
private static void convertCapabilities(Component component, TopologyTemplate topologyTemplate) {
convertTopologyTemplateCapabilities(component, topologyTemplate);
if (componentInstancesCapabilitiesExist(component) || groupsCapabilitiesExist(component)) {
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/UploadReqInfoTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/UploadReqInfoTest.java
deleted file mode 100644
index 8ce7d8db57..0000000000
--- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/UploadReqInfoTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-package org.openecomp.sdc.be.model;
-
-import static com.google.code.beanmatchers.BeanMatchers.hasValidGettersAndSetters;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import org.junit.Test;
-
-public class UploadReqInfoTest {
-
- @Test
- public void shouldHaveValidGettersAndSetters() {
- assertThat(UploadReqInfo.class, hasValidGettersAndSetters());
- }
-}
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverterTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverterTest.java
index 5aa742a540..871a43016f 100644
--- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverterTest.java
+++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverterTest.java
@@ -29,7 +29,6 @@
*/
package org.openecomp.sdc.be.model.jsonjanusgraph.utils;
-
import java.util.HashMap;
import org.junit.jupiter.api.Test;
@@ -38,6 +37,7 @@ import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
+import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
@@ -72,6 +72,9 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import org.openecomp.sdc.be.model.tosca.ToscaType;
+import org.openecomp.sdc.be.ui.model.OperationUi;
+import org.openecomp.sdc.be.ui.model.PropertyAssignmentUi;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -277,6 +280,49 @@ public class ModelConverterTest {
}
@Test
+ void testConvertRelationTemplateToToscaRelation()
+ {
+ RequirementCapabilityRelDef reqCap = new RequirementCapabilityRelDef();
+ reqCap.setOriginUI(true);
+ reqCap.setFromNode("fromNode");
+ reqCap.setToNode("toNode");
+ List<CapabilityRequirementRelationship> list = new LinkedList<>();
+ CapabilityRequirementRelationship relationship = new CapabilityRequirementRelationship();
+ RelationshipInfo info = new RelationshipInfo();
+ info.setCapabilityOwnerId("capOwnerId");
+ info.setId("id");
+ info.setCapabilityUid("capUid");
+ info.setRequirementOwnerId("reqOwnerId");
+ info.setRequirementUid("reqUid");
+ info.setRequirement("req");
+ info.setCapability("cap");
+ RelationshipImpl relationshipImpl = new RelationshipImpl();
+ relationshipImpl.setType("type");
+ info.setRelationships(relationshipImpl);
+ relationship.setRelation(info);
+ OperationUi operationUi = new OperationUi();
+ operationUi.setInterfaceType("tosca.interfaces.relationship.Configure");
+ operationUi.setOperationType("add_source");
+ final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition();
+ artifactDataDefinition.setArtifactName("impl");
+ operationUi.setImplementation(artifactDataDefinition);
+ PropertyAssignmentUi propertyAssignmentUi = new PropertyAssignmentUi();
+ propertyAssignmentUi.setName("strInput1");
+ propertyAssignmentUi.setType(ToscaType.STRING.getType());
+ propertyAssignmentUi.setValue("inputValue");
+ operationUi.setInputs(List.of(propertyAssignmentUi));
+ relationship.setOperations(List.of(operationUi));
+ list.add(relationship);
+ reqCap.setRelationships(list);
+
+ List<RelationshipInstDataDefinition> result = ModelConverter.convertRelationToToscaRelation(reqCap);
+ assertEquals(1, result.size());
+ assertEquals(false, result.get(0).getInterfaces().isEmpty());
+ assertEquals(false, result.get(0).getInterfaces().getListToscaDataDefinition().get(0).getOperations().isEmpty());
+ assertEquals(false, result.get(0).getInterfaces().getListToscaDataDefinition().get(0).getOperations().get("add_source").getInputs().isEmpty());
+ }
+
+ @Test
public void testConvertToMapOfMapCapabilityPropertiesonvertRelation()
{
Map<String, List<CapabilityDefinition>> capabilities = new HashMap<>();
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/utils/TypeUtils.java b/common-be/src/main/java/org/openecomp/sdc/be/utils/TypeUtils.java
index 92a9e3a144..cfbb6db76d 100644
--- a/common-be/src/main/java/org/openecomp/sdc/be/utils/TypeUtils.java
+++ b/common-be/src/main/java/org/openecomp/sdc/be/utils/TypeUtils.java
@@ -64,8 +64,9 @@ public class TypeUtils {
// Heat env Validation
PARAMETERS("parameters"),
// Import Validations
- TOSCA_VERSION("tosca_definitions_version"), TOPOLOGY_TEMPLATE("topology_template"), OCCURRENCES("occurrences"), NODE_TEMPLATES("node_templates"),
- GROUPS("groups"), INPUTS("inputs"), OUTPUTS("outputs"),
+ TOSCA_VERSION("tosca_definitions_version"), TOPOLOGY_TEMPLATE("topology_template"), OCCURRENCES("occurrences"),
+ NODE_TEMPLATES("node_templates"), GROUPS("groups"), INPUTS("inputs"),
+ OUTPUTS("outputs"), RELATIONSHIP_TEMPLATES("relationship_templates"),
SUBSTITUTION_MAPPINGS("substitution_mappings"), NODE_TYPE("node_type"), DIRECTIVES("directives"),
// Attributes
ATTRIBUTES("attributes"), LABEL("label"), HIDDEN("hidden"), IMMUTABLE("immutable"), ANNOTATIONS("annotations"),