aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/exception/ToscaExportException.java28
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java26
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java385
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandler.java83
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilder.java71
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaOperationAssignment.java34
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignment.java31
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationship.java35
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationshipTemplate.java40
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java20
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java70
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java41
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtil.java43
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java48
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java530
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandlerTest.java111
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilderTest.java122
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaRequirementTest.java67
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirementTest.java147
-rw-r--r--catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtilTest.java53
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationship.java26
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java77
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/utils/ModelConverter.java45
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/OperationUi.java43
-rw-r--r--catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/PropertyAssignmentUi.java31
-rw-r--r--catalog-model/src/test/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationshipTest.java93
-rw-r--r--catalog-ui/src/app/models/graph/match-relation.ts21
-rw-r--r--catalog-ui/src/app/models/graph/relationship.ts10
-rw-r--r--catalog-ui/src/app/models/properties-inputs/property-assignment.ts31
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts2
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/connection-wizard.module.ts43
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.html53
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.less73
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.spec.ts125
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.ts72
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.html141
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less211
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.spec.ts234
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.ts235
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/model/operation.ts39
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.css0
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.html118
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.spec.ts49
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.ts111
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.html35
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.less29
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.spec.ts66
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.ts163
-rw-r--r--catalog-ui/src/assets/languages/en_US.json13
-rw-r--r--common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/RelationshipInstDataDefinition.java9
50 files changed, 3436 insertions, 747 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/exception/ToscaExportException.java b/catalog-be/src/main/java/org/openecomp/sdc/be/exception/ToscaExportException.java
new file mode 100644
index 0000000000..66357c118e
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/exception/ToscaExportException.java
@@ -0,0 +1,28 @@
+/*
+ * ============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.exception;
+
+public class ToscaExportException extends Exception {
+
+ public ToscaExportException(String message) {
+ super(message);
+ }
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java
index 1f1dcfed8c..8fb835e0b9 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java
@@ -29,6 +29,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.commons.collections.MapUtils;
import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
@@ -155,12 +157,15 @@ public class InterfacesOperationsConverter {
Map<String, Object> toscaInterfaceDefinitions = new HashMap<>();
for (InterfaceDefinition interfaceDefinition : interfaces.values()) {
ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition();
- String interfaceType;
+ final String interfaceType;
if(componentInstance != null && LOCAL_INTERFACE_TYPE.equals(interfaceDefinition.getType())) {
interfaceType = DERIVED_FROM_BASE_DEFAULT + componentInstance.getSourceModelName();
} else {
interfaceType = getInterfaceType(component, interfaceDefinition.getType());
}
+ if (componentInstance == null) {
+ toscaInterfaceDefinition.setType(interfaceType);
+ }
toscaInterfaceDefinition.setType(interfaceType);
final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations();
Map<String, Object> toscaOperationMap = new HashMap<>();
@@ -204,6 +209,25 @@ public class InterfacesOperationsConverter {
return toscaInterfaceDefinitions;
}
+ public void removeInterfacesWithoutOperations(final Map<String, Object> interfaceMap) {
+ if (MapUtils.isEmpty(interfaceMap)) {
+ return;
+ }
+ final Set<String> emptyInterfaces = interfaceMap.entrySet().stream()
+ .filter(entry -> {
+ final Object value = entry.getValue();
+ if (value instanceof ToscaInterfaceDefinition) {
+ final ToscaInterfaceDefinition interfaceDefinition = (ToscaInterfaceDefinition) value;
+ return MapUtils.isEmpty(interfaceDefinition.getOperations());
+ } else if (value instanceof Map) {
+ final Map<String, Object> interfaceDefMap = (Map<String, Object>) value;
+ return MapUtils.isEmpty(interfaceDefMap);
+ }
+ return false;
+ }).map(Entry::getKey).collect(Collectors.toSet());
+ emptyInterfaces.forEach(interfaceMap::remove);
+ }
+
private Map<String, Object> createInterfaceInputMap(final InterfaceDefinition interfaceDefinition,
final Map<String, DataTypeDefinition> allDataTypeMap) {
final Map<String, InputDataDefinition> inputMap = interfaceDefinition.getInputs();
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
index 6131eb5850..b8da23085d 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java
@@ -20,17 +20,20 @@
package org.openecomp.sdc.be.tosca;
-import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
import static org.apache.commons.collections.MapUtils.isNotEmpty;
import static org.openecomp.sdc.be.components.utils.PropertiesUtils.resolvePropertyValueFromInput;
import static org.openecomp.sdc.be.tosca.InterfacesOperationsConverter.addInterfaceTypeElement;
+import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_ATTRIBUTE;
+import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_INPUT;
+import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_PROPERTY;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import fj.data.Either;
import java.beans.IntrospectionException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -71,8 +74,10 @@ 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.exception.ToscaExportException;
import org.openecomp.sdc.be.model.ArtifactDefinition;
import org.openecomp.sdc.be.model.CapabilityDefinition;
+import org.openecomp.sdc.be.model.CapabilityRequirementRelationship;
import org.openecomp.sdc.be.model.Component;
import org.openecomp.sdc.be.model.ComponentInstance;
import org.openecomp.sdc.be.model.ComponentInstanceInput;
@@ -95,7 +100,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade
import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
-import org.openecomp.sdc.be.model.tosca.converters.ToscaValueBaseConverter;
+import org.openecomp.sdc.be.tosca.builder.ToscaRelationshipBuilder;
import org.openecomp.sdc.be.tosca.model.CapabilityFilter;
import org.openecomp.sdc.be.tosca.model.NodeFilter;
import org.openecomp.sdc.be.tosca.model.SubstitutionMapping;
@@ -107,6 +112,8 @@ import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
import org.openecomp.sdc.be.tosca.model.ToscaPolicyTemplate;
import org.openecomp.sdc.be.tosca.model.ToscaProperty;
+import org.openecomp.sdc.be.tosca.model.ToscaPropertyAssignment;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationshipTemplate;
import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
import org.openecomp.sdc.be.tosca.model.ToscaTemplateArtifact;
@@ -330,6 +337,12 @@ public class ToscaExportHandler {
log.debug("node templates converted");
topologyTemplate.setNode_templates(nodeTemplates.left().value());
}
+ final Map<String, ToscaRelationshipTemplate> relationshipTemplatesMap =
+ new ToscaExportRelationshipTemplatesHandler()
+ .createFrom(topologyTemplate.getNode_templates());
+ if (!relationshipTemplatesMap.isEmpty()) {
+ topologyTemplate.setRelationshipTemplates(relationshipTemplatesMap);
+ }
SubstitutionMapping substitutionMapping = new SubstitutionMapping();
convertSubstitutionMappingFilter(component, substitutionMapping);
@@ -950,30 +963,31 @@ public class ToscaExportHandler {
String instanceUniqueId,
Component parentComponent) {
- Map<String, Object> interfaces;
-
+ final Map<String, Object> interfaceMap;
// we need to handle service proxy interfaces
if (isComponentOfTypeServiceProxy(componentInstance)) {
if (MapUtils.isEmpty(componentInstanceInterfaces)
|| !componentInstanceInterfaces.containsKey(instanceUniqueId)) {
- interfaces = null;
- } else {
- List<ComponentInstanceInterface> currServiceInterfaces =
- componentInstanceInterfaces.get(instanceUniqueId);
+ nodeTemplate.setInterfaces(null);
+ return;
+ }
- Map<String, InterfaceDefinition> tmpInterfaces = new HashMap<>();
- currServiceInterfaces.forEach(instInterface -> tmpInterfaces.put(instInterface
- .getUniqueId(), instInterface));
+ final List<ComponentInstanceInterface> currServiceInterfaces =
+ componentInstanceInterfaces.get(instanceUniqueId);
- interfaces = interfacesOperationsConverter
- .getInterfacesMap(parentComponent, componentInstance, tmpInterfaces, dataTypes, true, true);
- }
+ final Map<String, InterfaceDefinition> tmpInterfaces = new HashMap<>();
+ currServiceInterfaces.forEach(instInterface -> tmpInterfaces.put(instInterface
+ .getUniqueId(), instInterface));
+
+ interfaceMap = interfacesOperationsConverter
+ .getInterfacesMap(parentComponent, componentInstance, tmpInterfaces, dataTypes, true, true);
} else {
- interfaces =
+ interfaceMap =
getComponentInstanceInterfaceInstances(componentInstanceInterfaces,
componentInstance, instanceUniqueId);
}
- nodeTemplate.setInterfaces(interfaces);
+ interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
+ nodeTemplate.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap);
}
private boolean isComponentOfTypeServiceProxy(ComponentInstance componentInstance) {
@@ -1050,30 +1064,6 @@ public class ToscaExportHandler {
}
}
- /**
- *
- */
- private void convertAndAddValue(Map<String, DataTypeDefinition> dataTypes, ComponentInstance componentInstance,
- Map<String, Object> props, PropertyDefinition prop, Supplier<String> supplier) {
- Object convertedValue = convertValue(dataTypes, componentInstance, prop, supplier);
- if (!ToscaValueBaseConverter.isEmptyObjectValue(convertedValue)) {
- props.put(prop.getName(), convertedValue);
- }
- }
-
- private <T extends PropertyDefinition> Object convertValue(Map<String, DataTypeDefinition> dataTypes,
- ComponentInstance componentInstance, T input,
- Supplier<String> supplier) {
- log.debug("Convert property or input value {} for instance {}", input.getName(),
- componentInstance.getUniqueId());
- String propertyType = input.getType();
- String innerType = null;
- if (input.getSchema() != null && input.getSchema().getProperty() != null) {
- innerType = input.getSchema().getProperty().getType();
- }
- return propertyConvertor.convertToToscaObject(input, supplier.get(), dataTypes, true);
- }
-
private ToscaNodeType createNodeType(Component component) {
ToscaNodeType toscaNodeType = new ToscaNodeType();
if (ModelConverter.isAtomicComponent(component)) {
@@ -1265,7 +1255,11 @@ public class ToscaExportHandler {
proxyProperties.ifPresent(toscaNodeType::setProperties);
Optional<Map<String, Object>> proxyInterfaces = getProxyNodeTypeInterfaces(proxyComponent, dataTypes);
- proxyInterfaces.ifPresent(toscaNodeType::setInterfaces);
+ if (proxyInterfaces.isPresent()) {
+ final Map<String, Object> interfaceMap = proxyInterfaces.get();
+ interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
+ toscaNodeType.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap);
+ }
return toscaNodeType;
}
@@ -1277,92 +1271,110 @@ public class ToscaExportHandler {
Component originComponent,
Map<String, Component> componentCache) {
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
- if (!addRequirements(component, componentInstance, relations, originComponent, toscaRequirements,
- componentCache)) {
- log.debug("Failed to convert component instance requirements for the component instance {}. ",
- componentInstance.getName());
- return Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR);
- }
- if (!toscaRequirements.isEmpty()) {
- nodeTypeTemplate.setRequirements(toscaRequirements);
+ final List<Map<String, ToscaTemplateRequirement>> toscaRequirements;
+ final List<RequirementCapabilityRelDef> requirementDefinitionList = filterRequirements(componentInstance,
+ relations);
+ if (isNotEmpty(requirementDefinitionList)) {
+ try {
+ toscaRequirements = buildRequirements(component, componentInstance,
+ requirementDefinitionList, originComponent, componentCache);
+ if (!toscaRequirements.isEmpty()) {
+ nodeTypeTemplate.setRequirements(toscaRequirements);
+ }
+ } catch (final Exception e) {
+ log.debug("Failed to convert component instance requirements for the component instance {}. ",
+ componentInstance.getName(), e);
+ return Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR);
+ }
}
log.debug("Finished to convert requirements for the node type {} ", componentInstance.getName());
return Either.left(nodeTypeTemplate);
}
- private boolean addRequirements(Component component, ComponentInstance componentInstance,
- List<RequirementCapabilityRelDef> relations, Component originComponent,
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements,
- Map<String, Component> componentCache) {
- List<RequirementCapabilityRelDef> filteredRelations = relations.stream()
+ private List<Map<String, ToscaTemplateRequirement>> buildRequirements(final Component component,
+ final ComponentInstance componentInstance,
+ final List<RequirementCapabilityRelDef> filteredRelations,
+ final Component originComponent,
+ final Map<String, Component> componentCache)
+ throws ToscaExportException {
+
+ final List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
+ for (RequirementCapabilityRelDef relationshipDefinition : filteredRelations) {
+ final Map<String, ToscaTemplateRequirement> toscaTemplateRequirementMap =
+ buildRequirement(componentInstance, originComponent, component.getComponentInstances(),
+ relationshipDefinition, componentCache);
+ toscaRequirements.add(toscaTemplateRequirementMap);
+ }
+
+ return toscaRequirements;
+ }
+
+ private List<RequirementCapabilityRelDef> filterRequirements(ComponentInstance componentInstance,
+ List<RequirementCapabilityRelDef> relations) {
+ return relations.stream()
.filter(p -> componentInstance.getUniqueId().equals(p.getFromNode())).collect(Collectors.toList());
- return isEmpty(filteredRelations) ||
- filteredRelations.stream()
- .allMatch(
- rel -> addRequirement(componentInstance, originComponent, component.getComponentInstances(), rel,
- toscaRequirements, componentCache));
- }
-
- private boolean addRequirement(ComponentInstance fromInstance, Component fromOriginComponent,
- List<ComponentInstance> instancesList, RequirementCapabilityRelDef rel,
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements,
- Map<String, Component> componentCache) {
-
- boolean result = true;
- Map<String, List<RequirementDefinition>> reqMap = fromOriginComponent.getRequirements();
- RelationshipInfo reqAndRelationshipPair = rel.getRelationships().get(0).getRelation();
- Either<Component, StorageOperationStatus> getOriginRes = null;
- Optional<RequirementDefinition> reqOpt = Optional.empty();
- Component toOriginComponent = null;
- Optional<CapabilityDefinition> capOpt = Optional.empty();
-
- ComponentInstance toInstance = instancesList.stream().filter(i -> rel.getToNode().equals(i.getUniqueId()))
+ }
+
+ private Map<String, ToscaTemplateRequirement> buildRequirement(final ComponentInstance fromInstance,
+ final Component fromOriginComponent,
+ final List<ComponentInstance> instancesList,
+ final RequirementCapabilityRelDef relationshipDefinition,
+ final Map<String, Component> componentCache)
+ throws ToscaExportException {
+
+ final Map<String, List<RequirementDefinition>> reqMap = fromOriginComponent.getRequirements();
+ final CapabilityRequirementRelationship capabilityRequirementRelationship = relationshipDefinition
+ .getRelationships().get(0);
+ final RelationshipInfo relationshipInfo = capabilityRequirementRelationship.getRelation();
+
+ final ComponentInstance toInstance = instancesList.stream()
+ .filter(i -> relationshipDefinition.getToNode().equals(i.getUniqueId()))
.findFirst().orElse(null);
if (toInstance == null) {
- log.debug("Failed to find a relation from the node {} to the node {}", fromInstance.getName(),
- rel.getToNode());
- result = false;
- }
- if (result) {
- reqOpt = findRequirement(fromOriginComponent, reqMap, reqAndRelationshipPair, fromInstance.getUniqueId());
- if (!reqOpt.isPresent()) {
- log.debug("Failed to find a requirement with uniqueId {} on a component with uniqueId {}",
- reqAndRelationshipPair.getRequirementUid(), fromOriginComponent.getUniqueId());
- result = false;
+ final String errorMsg = String
+ .format("Failed to find a relation from the node %s to the node %s", fromInstance.getName(),
+ relationshipDefinition.getToNode());
+ log.debug(errorMsg);
+ throw new ToscaExportException(errorMsg);
+ }
+ final Optional<RequirementDefinition> reqOpt =
+ findRequirement(fromOriginComponent, reqMap, relationshipInfo, fromInstance.getUniqueId());
+ if (reqOpt.isEmpty()) {
+ final String errorMsg = String
+ .format("Failed to find a requirement with uniqueId %s on a component with uniqueId %s",
+ relationshipInfo.getRequirementUid(), fromOriginComponent.getUniqueId());
+ log.debug(errorMsg);
+ throw new ToscaExportException(errorMsg);
+ }
+ final ComponentParametersView filter = new ComponentParametersView(true);
+ filter.setIgnoreComponentInstances(false);
+ filter.setIgnoreCapabilities(false);
+ filter.setIgnoreGroups(false);
+ final Either<Component, StorageOperationStatus> getOriginRes =
+ toscaOperationFacade.getToscaElement(toInstance.getActualComponentUid(), filter);
+ if (getOriginRes.isRight()) {
+ final String errorMsg = String.format(
+ "Failed to build substituted name for the requirement %s. "
+ + "Failed to get an origin component with uniqueId %s",
+ reqOpt.get().getName(), toInstance.getActualComponentUid());
+ log.debug(errorMsg);
+ throw new ToscaExportException(errorMsg);
+ }
+ final Component toOriginComponent = getOriginRes.left().value();
+ Optional<CapabilityDefinition> capOpt = toOriginComponent.getCapabilities().get(reqOpt.get().getCapability()).stream()
+ .filter(c -> isCapabilityBelongToRelation(relationshipInfo, c)).findFirst();
+ if (capOpt.isEmpty()) {
+ capOpt = findCapability(relationshipInfo, toOriginComponent, fromOriginComponent, reqOpt.get());
+ if (capOpt.isEmpty()) {
+ final String errorMsg = String
+ .format("Failed to find a capability with name %s on a component with uniqueId %s",
+ relationshipInfo.getCapability(), fromOriginComponent.getUniqueId());
+ log.debug(errorMsg);
+ throw new ToscaExportException(errorMsg);
}
}
- if (result) {
- ComponentParametersView filter = new ComponentParametersView(true);
- filter.setIgnoreComponentInstances(false);
- filter.setIgnoreCapabilities(false);
- filter.setIgnoreGroups(false);
- getOriginRes = toscaOperationFacade.getToscaElement(toInstance.getActualComponentUid(), filter);
- if (getOriginRes.isRight()) {
- log.debug(
- "Failed to build substituted name for the requirement {}. Failed to get an origin component with uniqueId {}",
- reqOpt.get().getName(), toInstance.getActualComponentUid());
- result = false;
- }
- }
- if (result) {
- toOriginComponent = getOriginRes.left().value();
- capOpt = toOriginComponent.getCapabilities().get(reqOpt.get().getCapability()).stream()
- .filter(c -> isCapabilityBelongToRelation(reqAndRelationshipPair, c)).findFirst();
- if (!capOpt.isPresent()) {
- capOpt = findCapability(reqAndRelationshipPair, toOriginComponent, fromOriginComponent, reqOpt.get());
- if (!capOpt.isPresent()) {
- result = false;
- log.debug("Failed to find a capability with name {} on a component with uniqueId {}",
- reqAndRelationshipPair.getCapability(), fromOriginComponent.getUniqueId());
- }
- }
- }
- if (result) {
- result = buildAndAddRequirement(toscaRequirements, fromOriginComponent, toOriginComponent, capOpt.get(),
- reqOpt.get(), reqAndRelationshipPair, toInstance, componentCache);
- }
- return result;
+ return buildRequirement(fromOriginComponent, toOriginComponent, capOpt.get(), reqOpt.get(),
+ capabilityRequirementRelationship, toInstance, componentCache);
}
private boolean isCapabilityBelongToRelation(RelationshipInfo reqAndRelationshipPair,
@@ -1383,40 +1395,50 @@ public class ToscaExportHandler {
return cap;
}
- private boolean buildAndAddRequirement(List<Map<String, ToscaTemplateRequirement>> toscaRequirements,
- Component fromOriginComponent, Component toOriginComponent,
- CapabilityDefinition capability, RequirementDefinition requirement,
- RelationshipInfo reqAndRelationshipPair, ComponentInstance toInstance,
- Map<String, Component> componentCache) {
+ private Map<String, ToscaTemplateRequirement> buildRequirement(final Component fromOriginComponent,
+ final Component toOriginComponent,
+ final CapabilityDefinition capability,
+ final RequirementDefinition requirement,
+ final CapabilityRequirementRelationship capabilityRequirementRelationship,
+ final ComponentInstance toInstance,
+ final Map<String, Component> componentCache)
+ throws ToscaExportException {
+
List<String> reducedPath = capability.getPath();
if (capability.getOwnerId() != null) {
reducedPath = capabilityRequirementConverter
.getReducedPathByOwner(capability.getPath(), capability.getOwnerId());
}
- Either<String, Boolean> buildCapNameRes = capabilityRequirementConverter.buildSubstitutedName(componentCache,
- toOriginComponent, reducedPath, reqAndRelationshipPair.getCapability(), capability.getPreviousName());
- if (buildCapNameRes.isRight()) {
+ final RelationshipInfo relationshipInfo = capabilityRequirementRelationship.getRelation();
+ final Either<String, Boolean> capabilityNameEither = capabilityRequirementConverter.buildSubstitutedName(componentCache,
+ toOriginComponent, reducedPath, relationshipInfo.getCapability(), capability.getPreviousName());
+ if (capabilityNameEither.isRight()) {
+ final String errorMsg = String.format(
+ "Failed to build a substituted capability name for the capability with name %s on a component with uniqueId %s",
+ capabilityRequirementRelationship.getCapability(), toOriginComponent.getUniqueId());
log.debug(
- "Failed to build a substituted capability name for the capability with name {} on a component with uniqueId {}",
- reqAndRelationshipPair.getCapability(), fromOriginComponent.getUniqueId());
- return false;
+ errorMsg);
+ throw new ToscaExportException(errorMsg);
}
- Either<String, Boolean> buildReqNameRes = capabilityRequirementConverter
+ final Either<String, Boolean> requirementNameEither = capabilityRequirementConverter
.buildSubstitutedName(componentCache, fromOriginComponent,
- requirement.getPath(), reqAndRelationshipPair.getRequirement(), requirement.getPreviousName());
- if (buildReqNameRes.isRight()) {
- log.debug(
- "Failed to build a substituted requirement name for the requirement with name {} on a component with uniqueId {}",
- reqAndRelationshipPair.getRequirement(), fromOriginComponent.getUniqueId());
- return false;
- }
- ToscaTemplateRequirement toscaRequirement = new ToscaTemplateRequirement();
- Map<String, ToscaTemplateRequirement> toscaReqMap = new HashMap<>();
+ requirement.getPath(), relationshipInfo.getRequirement(), requirement.getPreviousName());
+ if (requirementNameEither.isRight()) {
+ final String errorMsg = String.format("Failed to build a substituted requirement name for the requirement "
+ + "with name %s on a component with uniqueId %s",
+ capabilityRequirementRelationship.getRequirement(), fromOriginComponent.getUniqueId());
+ log.debug(errorMsg);
+ throw new ToscaExportException(errorMsg);
+ }
+ final ToscaTemplateRequirement toscaRequirement = new ToscaTemplateRequirement();
+ final Map<String, ToscaTemplateRequirement> toscaReqMap = new HashMap<>();
toscaRequirement.setNode(toInstance.getName());
- toscaRequirement.setCapability(buildCapNameRes.left().value());
- toscaReqMap.put(buildReqNameRes.left().value(), toscaRequirement);
- toscaRequirements.add(toscaReqMap);
- return true;
+ toscaRequirement.setCapability(capabilityNameEither.left().value());
+ if (isNotEmpty(capabilityRequirementRelationship.getOperations())) {
+ toscaRequirement.setRelationship(new ToscaRelationshipBuilder().from(capabilityRequirementRelationship));
+ }
+ toscaReqMap.put(requirementNameEither.left().value(), toscaRequirement);
+ return toscaReqMap;
}
private Optional<RequirementDefinition> findRequirement(Component fromOriginComponent,
@@ -1673,12 +1695,83 @@ public class ToscaExportHandler {
CustomRepresenter() {
super();
+ this.representers.put(ToscaPropertyAssignment.class, new RepresentToscaPropertyAssignment());
// null representer is exceptional and it is stored as an instance
// variable.
this.nullRepresenter = new RepresentNull();
}
+ private class RepresentToscaPropertyAssignment implements Represent {
+ public Node representData(Object data) {
+ final ToscaPropertyAssignment toscaOperationAssignment = (ToscaPropertyAssignment) data;
+ if (toscaOperationAssignment.getValue() instanceof String) {
+ final String stringValue = (String) toscaOperationAssignment.getValue();
+ if (isPropertyOrAttributeFunction(stringValue)) {
+ return representGetAttribute(stringValue);
+ }
+
+ return representScalar(Tag.STR, stringValue);
+ }
+ return represent(null);
+ }
+
+ public Node representGetAttribute(final String getAttributeFunction) {
+ return represent(new Yaml().load(getAttributeFunction));
+ }
+
+ public boolean isPropertyOrAttributeFunction(final String value) {
+ try {
+ final Yaml yaml = new Yaml();
+ final Object yamlObj = yaml.load(value);
+ if (!(yamlObj instanceof Map)) {
+ return false;
+ }
+ final Map<String, Object> getAttributeMap = (Map) yamlObj;
+ if (getAttributeMap.size() != 1) {
+ return false;
+ }
+ final List<String> functionList = Arrays
+ .asList(GET_ATTRIBUTE.getFunctionName(), GET_INPUT.getFunctionName(),
+ GET_PROPERTY.getFunctionName());
+ final Optional<String> function = getAttributeMap.keySet().stream()
+ .filter(key -> functionList.stream().anyMatch(function1 -> function1.equals(key))).findFirst();
+
+ if (function.isEmpty()) {
+ return false;
+ }
+ final String functionName = function.get();
+ final Object getAttributeValueObj = getAttributeMap.get(functionName);
+ if (GET_INPUT.getFunctionName().equals(functionName)) {
+ return validateGetInputValue(getAttributeValueObj);
+ } else {
+ return validateGetPropertyOrAttributeValue(getAttributeValueObj);
+ }
+ } catch (final Exception ignored) {
+ return false;
+ }
+ }
+ }
+
+ public boolean validateGetInputValue(final Object valueObj) {
+ if (!(valueObj instanceof List) && !(valueObj instanceof String)) {
+ return false;
+ }
+ if (valueObj instanceof List) {
+ return ((List) valueObj).size() > 1;
+ }
+
+ return true;
+ }
+
+ public boolean validateGetPropertyOrAttributeValue(final Object valueObj) {
+ if (valueObj instanceof List) {
+ return ((List) valueObj).size() > 1;
+ }
+
+ return false;
+ }
+
@Override
protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue,
Tag customTag) {
@@ -1689,9 +1782,17 @@ public class ToscaExportHandler {
if ("dependencies".equals(property.getName())) {
return null;
}
+ if (javaBean instanceof ToscaRelationshipTemplate && "name".equals(property.getName())) {
+ return null;
+ }
+
removeDefaultP(propertyValue);
NodeTuple defaultNode = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ if (javaBean instanceof ToscaTopolgyTemplate && "relationshipTemplates".equals(property.getName())) {
+ return new NodeTuple(representData("relationship_templates"), defaultNode.getValueNode());
+ }
+
return "_defaultp_".equals(property.getName())
? new NodeTuple(representData("default"), defaultNode.getValueNode()) : defaultNode;
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandler.java
new file mode 100644
index 0000000000..c706063d75
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandler.java
@@ -0,0 +1,83 @@
+/*
+ * ============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.tosca;
+
+import static org.apache.commons.collections.CollectionUtils.isEmpty;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.commons.collections.MapUtils;
+import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationship;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationshipTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement;
+
+/**
+ * Handles the relationship_templates in the TOSCA export
+ */
+public class ToscaExportRelationshipTemplatesHandler {
+
+ /**
+ * Creates the relationship_templates map based on the node_templates requirements.
+ *
+ * @param nodeTemplateMap the node template map
+ * @return the relationship_templates map
+ */
+ public Map<String, ToscaRelationshipTemplate> createFrom(final Map<String, ToscaNodeTemplate> nodeTemplateMap) {
+ if (MapUtils.isEmpty(nodeTemplateMap)) {
+ return Collections.emptyMap();
+ }
+
+ final Map<String, ToscaRelationshipTemplate> relationshipTemplates = new HashMap<>();
+ for (final Entry<String, ToscaNodeTemplate> nodeEntry : nodeTemplateMap.entrySet()) {
+ final ToscaNodeTemplate nodeTemplate = nodeEntry.getValue();
+ if (isEmpty(nodeTemplate.getRequirements())) {
+ continue;
+ }
+ final AtomicInteger relationshipTemplateCount = new AtomicInteger(1);
+ for (final Map<String, ToscaTemplateRequirement> requirementMap : nodeTemplate.getRequirements()) {
+ requirementMap.entrySet().stream()
+ .filter(entry -> entry.getValue().isRelationshipComplexNotation())
+ .forEach(requirementEntry -> {
+ final ToscaTemplateRequirement requirement = requirementEntry.getValue();
+ final ToscaRelationship relationship = requirement.getRelationshipAsComplexType();
+ final ToscaRelationshipTemplate relationshipTemplate = new ToscaRelationshipTemplate();
+ relationshipTemplate.setType(relationship.getType());
+ relationshipTemplate.setInterfaces(relationship.getInterfaces());
+ final String relationshipName = String.format("%s.%s",
+ ToscaRelationshipTemplate
+ .createRelationshipName(nodeEntry.getKey(), requirementEntry.getKey()),
+ relationshipTemplateCount);
+
+ requirement.setRelationship(relationshipName);
+ relationshipTemplate.setName(relationshipName);
+ relationshipTemplates.put(relationshipName, relationshipTemplate);
+ relationshipTemplateCount.incrementAndGet();
+ });
+ }
+ }
+
+ return relationshipTemplates;
+ }
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilder.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilder.java
new file mode 100644
index 0000000000..c3c9607664
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilder.java
@@ -0,0 +1,71 @@
+/*
+ * ============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.tosca.builder;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import org.apache.commons.collections.CollectionUtils;
+import org.openecomp.sdc.be.model.CapabilityRequirementRelationship;
+import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
+import org.openecomp.sdc.be.tosca.model.ToscaOperationAssignment;
+import org.openecomp.sdc.be.tosca.model.ToscaPropertyAssignment;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationship;
+import org.openecomp.sdc.be.tosca.utils.InterfaceTypesNameUtil;
+import org.openecomp.sdc.be.ui.model.OperationUi;
+
+public class ToscaRelationshipBuilder {
+
+ public ToscaRelationship from(final CapabilityRequirementRelationship capabilityRequirementRelationship) {
+ final ToscaRelationship toscaRelationship = new ToscaRelationship();
+ final List<OperationUi> operations = capabilityRequirementRelationship.getOperations();
+ toscaRelationship.setType(capabilityRequirementRelationship.getRelation().getRelationship().getType());
+ final Map<String, List<OperationUi>> operationsByInterfaceType = operations.stream()
+ .collect(Collectors.groupingBy(OperationUi::getInterfaceType));
+ final Map<String, ToscaInterfaceDefinition> interfaceMap = new HashMap<>();
+ for (final Entry<String, List<OperationUi>> interfaceTypeEntry : operationsByInterfaceType.entrySet()) {
+ final ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition();
+ final String interfaceType = interfaceTypeEntry.getKey();
+ final Map<String, Object> operationDefinitionMap = new HashMap<>();
+ for (final OperationUi operationUi : interfaceTypeEntry.getValue()) {
+ final ToscaOperationAssignment toscaOperationAssignment = new ToscaOperationAssignment();
+ toscaOperationAssignment.setImplementation(operationUi.getImplementation());
+ if (CollectionUtils.isNotEmpty(operationUi.getInputs())) {
+ final Map<String, ToscaPropertyAssignment> inputMap = new HashMap<>();
+ operationUi.getInputs().forEach(propertyAssignmentUi -> {
+ final ToscaPropertyAssignment toscaProperty = new ToscaPropertyAssignment();
+ toscaProperty.setValue(propertyAssignmentUi.getValue());
+ inputMap.put(propertyAssignmentUi.getName(), toscaProperty);
+ });
+
+ toscaOperationAssignment.setInputs(inputMap);
+ }
+ operationDefinitionMap.put(operationUi.getOperationType(), toscaOperationAssignment);
+ }
+ toscaInterfaceDefinition.setOperations(operationDefinitionMap);
+ interfaceMap.put(InterfaceTypesNameUtil.buildShortName(interfaceType), toscaInterfaceDefinition);
+ }
+ toscaRelationship.setInterfaces(interfaceMap);
+ return toscaRelationship;
+ }
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaOperationAssignment.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaOperationAssignment.java
new file mode 100644
index 0000000000..2aba85027e
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaOperationAssignment.java
@@ -0,0 +1,34 @@
+/*
+ * ============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.tosca.model;
+
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ToscaOperationAssignment {
+
+ private String description;
+ private String implementation;
+ private Map<String, ToscaPropertyAssignment> inputs;
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignment.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignment.java
new file mode 100644
index 0000000000..f42b655cbf
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignment.java
@@ -0,0 +1,31 @@
+/*
+ * ============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.tosca.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ToscaPropertyAssignment {
+
+ private Object value;
+
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationship.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationship.java
new file mode 100644
index 0000000000..49286ca0e2
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationship.java
@@ -0,0 +1,35 @@
+/*
+ * ============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.tosca.model;
+
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Represents a relationship entry in a requirement fulfilment.
+ */
+@Getter
+@Setter
+public class ToscaRelationship {
+
+ private String type;
+ private Map<String, ToscaInterfaceDefinition> interfaces;
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationshipTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationshipTemplate.java
new file mode 100644
index 0000000000..f42effab6b
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRelationshipTemplate.java
@@ -0,0 +1,40 @@
+/*
+ * ============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.tosca.model;
+
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Represents a relationship_template in the topology_template.
+ */
+@Getter
+@Setter
+public class ToscaRelationshipTemplate {
+
+ private String name;
+ private String type;
+ private Map<String, ToscaInterfaceDefinition> interfaces;
+
+ public static String createRelationshipName(final String nodeName, final String requirementName) {
+ return String.format("%s.%s", nodeName, requirementName);
+ }
+}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java
index 35d5c4e6e1..c8e0527191 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaRequirement.java
@@ -21,25 +21,13 @@
package org.openecomp.sdc.be.tosca.model;
import java.util.List;
-import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+@Getter
+@Setter
public class ToscaRequirement extends ToscaTemplateRequirement {
private List<Object> occurrences;
- public ToscaRequirement() {
- }
-
- public List<Object> getOccurrences() {
- return occurrences;
- }
-
- public void setOccurrences(List<Object> occurrences) {
- this.occurrences = occurrences;
- }
-
- public Map<String, Object> toMap() throws IllegalArgumentException, IllegalAccessException {
- return super.toMap();
- }
-
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java
index 7a77c4f47c..85d01e1469 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirement.java
@@ -20,49 +20,51 @@
package org.openecomp.sdc.be.tosca.model;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+import org.openecomp.sdc.exception.InvalidArgumentException;
+@Getter
+@Setter
public class ToscaTemplateRequirement {
private String capability;
private String node;
- private String relationship;
+ private Object relationship;
- public ToscaTemplateRequirement() {
- }
-
- public String getCapability() {
- return capability;
- }
-
- public void setCapability(String capability) {
- this.capability = capability;
- }
-
- public String getNode() {
- return node;
- }
-
- public void setNode(String node) {
- this.node = node;
- }
-
- public String getRelationship() {
- return relationship;
+ public ToscaRelationship getRelationshipAsComplexType() {
+ if (relationship == null) {
+ return null;
+ }
+ if (relationship instanceof ToscaRelationship) {
+ return (ToscaRelationship) relationship;
+ }
+ final ToscaRelationship toscaRelationship = new ToscaRelationship();
+ toscaRelationship.setType((String) relationship);
+ return toscaRelationship;
}
- public void setRelationship(String relationship) {
+ public void setRelationship(final Object relationship) {
+ if (relationship == null) {
+ this.relationship = null;
+ return;
+ }
+ if (!(relationship instanceof ToscaRelationship) && !(relationship instanceof String)) {
+ throw new InvalidArgumentException(String.format("relationship %s type not expected. "
+ + "Supported types are %s and %s", relationship.getClass(), ToscaRelationship.class, String.class));
+ }
this.relationship = relationship;
}
- public Map<String, Object> toMap() throws IllegalArgumentException, IllegalAccessException {
- Map<String, Object> map = new HashMap<>();
- Field[] fields = this.getClass().getDeclaredFields();
- for (Field field : fields) {
- field.setAccessible(true);
- map.put(field.getName(), field.get(this));
- }
- return map;
+ /**
+ * Checks if the relationship entry is a complex type ({@link ToscaRelationship}).
+ *
+ * The relationship can be a simple notation (string) (see Tosca 1.3, Section 3.7.3.2.2), or a multi-line grammar
+ * notation (complex) (see Tosca 1.3, Section 3.7.3.2.3).
+ *
+ * @return {@code true} if the relationship is a complex type, {@code false} otherwise
+ */
+ public boolean isRelationshipComplexNotation() {
+ return relationship instanceof ToscaRelationship;
}
+
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java
index 0d62521e59..00ab08b677 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaTopolgyTemplate.java
@@ -22,25 +22,22 @@ package org.openecomp.sdc.be.tosca.model;
import java.util.HashMap;
import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+@Getter
public class ToscaTopolgyTemplate {
+
+ @Setter
private Map<String, ToscaProperty> inputs;
+ @Setter
private Map<String, ToscaNodeTemplate> node_templates;
private Map<String, ToscaGroupTemplate> groups;
private Map<String, ToscaPolicyTemplate> policies;
+ @Setter
private SubstitutionMapping substitution_mappings;
-
- public Map<String, ToscaNodeTemplate> getNode_templates() {
- return node_templates;
- }
-
- public void setNode_templates(Map<String, ToscaNodeTemplate> node_templates) {
- this.node_templates = node_templates;
- }
-
- public Map<String, ToscaGroupTemplate> getGroups() {
- return groups;
- }
+ @Setter
+ private Map<String, ToscaRelationshipTemplate> relationshipTemplates;
public void addGroups(Map<String, ToscaGroupTemplate> groups) {
if ( this.groups == null ){
@@ -49,30 +46,10 @@ public class ToscaTopolgyTemplate {
this.groups.putAll(groups);
}
- public SubstitutionMapping getSubstitution_mappings() {
- return substitution_mappings;
- }
-
- public void setSubstitution_mappings(SubstitutionMapping substitution_mapping) {
- this.substitution_mappings = substitution_mapping;
- }
-
- public Map<String, ToscaProperty> getInputs() {
- return inputs;
- }
-
- public void setInputs(Map<String, ToscaProperty> inputs) {
- this.inputs = inputs;
- }
-
public void addPolicies(Map<String, ToscaPolicyTemplate> policiesMap) {
if ( this.policies == null ){
this.policies = new HashMap<>();
}
this.policies.putAll(policiesMap);
}
-
- public Map<String, ToscaPolicyTemplate> getPolicies() {
- return policies;
- }
}
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtil.java
new file mode 100644
index 0000000000..eda8cef250
--- /dev/null
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtil.java
@@ -0,0 +1,43 @@
+/*
+ * ============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.tosca.utils;
+
+public class InterfaceTypesNameUtil {
+
+ private InterfaceTypesNameUtil() {
+
+ }
+
+ /**
+ * Build the short name of an interface_type by grabbing the final name in its path. E.g.
+ * "tosca.interfaces.relationship.Configure" will be shortened to "Configure".
+ *
+ * @param interfaceName the full interface name
+ * @return the shortened name of the interface
+ */
+ public static String buildShortName(final String interfaceName) {
+ if (interfaceName == null) {
+ throw new IllegalArgumentException("interfaceName cannot be null");
+ }
+ final int index = interfaceName.lastIndexOf('.');
+ return index > 0 && interfaceName.length() > index + 1 ? interfaceName.substring(index + 1) : interfaceName;
+ }
+
+}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java
index 0281317b89..4f569f91cd 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java
@@ -21,9 +21,12 @@ package org.openecomp.sdc.be.tosca;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.anEmptyMap;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -70,6 +73,7 @@ import org.openecomp.sdc.be.model.InterfaceDefinition;
import org.openecomp.sdc.be.model.Resource;
import org.openecomp.sdc.be.model.Service;
import org.openecomp.sdc.be.model.ServiceMetadataDefinition;
+import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
import org.openecomp.sdc.common.util.YamlToObjectConverter;
@@ -666,4 +670,48 @@ class InterfacesOperationsConverterTest {
assertTrue(MapUtils.isNotEmpty(resultMap)
&& resultMap.containsKey("NotLocal"));
}
+
+ @Test
+ void testRemoveInterfacesWithoutOperationsEmptyMap() {
+ final Map<String, Object> interfaceMap = new HashMap<>();
+ interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
+ assertThat(interfaceMap, is(anEmptyMap()));
+ }
+
+ @Test
+ void testRemoveInterfacesWithoutOperationsNullParameter() {
+ final Map<String, Object> interfaceMap = null;
+ interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
+ assertThat(interfaceMap, is(nullValue()));
+ }
+
+ @Test
+ void testRemoveInterfacesWithoutOperationsSuccess() {
+ final Map<String, Object> interfaceMap = new HashMap<>();
+ final ToscaInterfaceDefinition toscaInterfaceDefinition1 = new ToscaInterfaceDefinition();
+ interfaceMap.put("toscaInterfaceDefinition1", toscaInterfaceDefinition1);
+
+ final ToscaInterfaceDefinition toscaInterfaceDefinition2 = new ToscaInterfaceDefinition();
+ final Map<String, Object> toscaInterfaceDefinition2OperationMap = new HashMap<>();
+ toscaInterfaceDefinition2OperationMap.put("operation1", new Object());
+ toscaInterfaceDefinition2.setOperations(toscaInterfaceDefinition2OperationMap);
+ interfaceMap.put("toscaInterfaceDefinition2", toscaInterfaceDefinition2);
+
+ final Map<String, Object> toscaInterfaceDefinition3 = new HashMap<>();
+ interfaceMap.put("toscaInterfaceDefinition3", toscaInterfaceDefinition3);
+
+ final Map<String, Object> toscaInterfaceDefinition4 = new HashMap<>();
+ toscaInterfaceDefinition4.put("operation1", new Object());
+ interfaceMap.put("toscaInterfaceDefinition4", toscaInterfaceDefinition4);
+
+ final Object notAToscaInterfaceDefinition = new Object();
+ interfaceMap.put("notAToscaInterfaceDefinition", notAToscaInterfaceDefinition);
+
+ interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
+ assertFalse(interfaceMap.containsKey("toscaInterfaceDefinition1"));
+ assertTrue(interfaceMap.containsKey("toscaInterfaceDefinition2"));
+ assertFalse(interfaceMap.containsKey("toscaInterfaceDefinition3"));
+ assertTrue(interfaceMap.containsKey("toscaInterfaceDefinition4"));
+ assertTrue(interfaceMap.containsKey("notAToscaInterfaceDefinition"));
+ }
}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java
index b03e12fb6e..a87460fa93 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java
@@ -16,12 +16,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
* ============LICENSE_END=========================================================
+ * Modifications copyright (c) 2020, Nordix Foundation
+ * ================================================================================
*/
package org.openecomp.sdc.be.tosca;
import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyList;
@@ -30,6 +37,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
import static org.openecomp.sdc.be.tosca.PropertyConvertor.PropertyType.PROPERTY;
import fj.data.Either;
@@ -50,7 +58,6 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.openecomp.sdc.be.components.BeConfDependentTest;
import org.openecomp.sdc.be.components.utils.PropertyDataDefinitionBuilder;
@@ -65,6 +72,7 @@ import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ToscaArtifactDataDefinition;
import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
+import org.openecomp.sdc.be.exception.ToscaExportException;
import org.openecomp.sdc.be.model.ArtifactDefinition;
import org.openecomp.sdc.be.model.CapabilityDefinition;
import org.openecomp.sdc.be.model.CapabilityRequirementRelationship;
@@ -122,7 +130,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
private ToscaOperationFacade toscaOperationFacade;
@Mock
- private CapabilityRequirementConverter capabiltyRequirementConvertor;
+ private CapabilityRequirementConverter capabilityRequirementConverter;
@Mock
private InputConverter inputConverter;
@@ -146,7 +154,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
private PolicyExportParser policyExportParser;
@Before
- public void setUpMock() throws Exception {
+ public void setUpMock() {
MockitoAnnotations.initMocks(this);
doReturn(new ToscaProperty()).when(propertyConvertor).convertProperty(any(), any(), eq(PROPERTY));
doReturn(new HashMap<String, Object>()).when(interfacesOperationsConverter)
@@ -217,11 +225,10 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
Component component = getNewResource();
Either<ToscaRepresentation, ToscaError> result;
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Resource.class),
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Resource.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
// default test when component is Resource
@@ -229,10 +236,9 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
Assert.assertNotNull(result);
component = getNewService();
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Service.class),
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Service.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+ when(dataTypeCache.getAll()).thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
// default test when component is Service
result = testSubject.exportComponent(component);
@@ -246,16 +252,15 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
((Resource) component).setInterfaces(new HashMap<>());
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(dataTypeCache.getAll()).thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND));
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
// default test when convertInterfaceNodeType is right
result = testSubject.exportComponentInterface(component, false);
Assert.assertNotNull(result);
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Resource.class),
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Resource.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
// default test when convertInterfaceNodeType is left
@@ -280,12 +285,11 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
component.setName(RESOURCE_NAME);
component.setToscaResourceName(RESOURCE_NAME);
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
// when convertRequirements is called, make it return the same value as 3rd (index=2) argument.
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Resource.class),
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Resource.class),
any(ToscaNodeType.class))).thenAnswer(i -> Either.left(i.getArgument(2)));
Either<ToscaTemplate, ToscaError> result = (Either<ToscaTemplate, ToscaError>) Deencapsulation
@@ -339,8 +343,8 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
component.setComponentInstances(resourceInstances);
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito.when(capabiltyRequirementConvertor.getOriginComponent(any(Map.class),
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(capabilityRequirementConverter.getOriginComponent(any(Map.class),
any(ComponentInstance.class))).thenReturn(Either.right(false));
// default test
@@ -368,19 +372,18 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
String[] array = {"value1", "value2"};
substitutionMappingMap.put("key", array);
- Mockito.when(capabiltyRequirementConvertor.convertSubstitutionMappingCapabilities(any(Map.class),
+ when(capabilityRequirementConverter.convertSubstitutionMappingCapabilities(any(Map.class),
any(Component.class))).thenReturn(Either.left(substitutionMappingMap));
- Mockito.when(capabiltyRequirementConvertor.convertSubstitutionMappingRequirements(any(Map.class),
+ when(capabilityRequirementConverter.convertSubstitutionMappingRequirements(any(Map.class),
any(Component.class), any(SubstitutionMapping.class)))
.thenReturn(Either.left(new SubstitutionMapping()));
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito.when(inputConverter.convertInputs(any(List.class), any(Map.class)))
- .thenReturn(new HashMap<>());
+ when(inputConverter.convertInputs(any(List.class), any(Map.class))).thenReturn(new HashMap<>());
- Mockito.when(groupExportParser.getGroups(component))
+ when(groupExportParser.getGroups(component))
.thenReturn(null);
// test component contains group
@@ -408,17 +411,16 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
String[] array = {"value1", "value2"};
substitutionMappingMap.put("key", array);
- Mockito
- .when(capabiltyRequirementConvertor.convertSubstitutionMappingCapabilities(anyMap(), any(Component.class)))
+ when(capabilityRequirementConverter.convertSubstitutionMappingCapabilities(anyMap(), any(Component.class)))
.thenReturn(Either.left(substitutionMappingMap));
- Mockito.when(capabiltyRequirementConvertor
+ when(capabilityRequirementConverter
.convertSubstitutionMappingRequirements(anyMap(), any(Component.class), any(SubstitutionMapping.class)))
.thenReturn(Either.left(new SubstitutionMapping()));
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito.when(inputConverter.convertInputs(anyList(), anyMap())).thenReturn(new HashMap<>());
+ when(inputConverter.convertInputs(anyList(), anyMap())).thenReturn(new HashMap<>());
// test component contains group
result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode);
Assert.assertNotNull(result);
@@ -456,7 +458,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
toscaArtifacts.put("assettoscatemplate", artifact);
component.setToscaArtifacts(toscaArtifacts);
- Mockito.when(toscaOperationFacade.getToscaFullElement(any(String.class)))
+ when(toscaOperationFacade.getToscaFullElement(any(String.class)))
.thenReturn(Either.left(component));
// default test
@@ -482,9 +484,9 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
ci.setOriginType(OriginTypeEnum.ServiceProxy);
ci.setSourceModelUid("modelName");
- Mockito.when(toscaOperationFacade.getToscaFullElement(eq("name"))).thenReturn(Either.left(component));
+ when(toscaOperationFacade.getToscaFullElement(eq("name"))).thenReturn(Either.left(component));
- Mockito.when(toscaOperationFacade.getToscaFullElement(eq("modelName")))
+ when(toscaOperationFacade.getToscaFullElement(eq("modelName")))
.thenReturn(Either.left(new Service()));
// default test
@@ -508,8 +510,8 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
Map<String, ToscaNodeType> nodeTypes = new HashMap<>();
Either<ToscaTemplate, ToscaError> result;
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.right(JanusGraphOperationStatus.ALREADY_EXIST));
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(dataTypeCache.getAll()).thenReturn(Either.right(JanusGraphOperationStatus.ALREADY_EXIST));
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
// default test
result = Deencapsulation
@@ -527,12 +529,11 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
inputs.add(new InputDefinition());
component.setInputs(inputs);
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Resource.class),
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Resource.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
// default test
@@ -550,13 +551,12 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
Map<String, DataTypeDefinition> dataTypes = new HashMap<>();
Either<ToscaTemplate, ToscaError> result;
- Mockito.when(
- capabiltyRequirementConvertor
+ when(
+ capabilityRequirementConverter
.convertCapabilities(any(Map.class), any(Resource.class), any(Map.class)))
.thenReturn(new HashMap<>());
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Resource.class),
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Resource.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
// default test
@@ -567,8 +567,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
component = new Service();
- Mockito
- .when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Service.class),
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Service.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
// test when component is service
@@ -621,10 +620,10 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstancesProperties.put("id", new ArrayList<>());
componentInstancesInputs.put("id", new ArrayList<>());
- Mockito.when(capabiltyRequirementConvertor.getOriginComponent(any(Map.class),
+ when(capabilityRequirementConverter.getOriginComponent(any(Map.class),
any(ComponentInstance.class))).thenReturn(Either.left(component));
- Mockito.when(capabiltyRequirementConvertor.convertComponentInstanceCapabilities(
+ when(capabilityRequirementConverter.convertComponentInstanceCapabilities(
any(ComponentInstance.class), any(Map.class), any(ToscaNodeTemplate.class)))
.thenReturn(Either.left(new ToscaNodeTemplate()));
@@ -687,10 +686,10 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstancesInterfaces.put("id", new ArrayList<>());
componentInstancesInputs.put("id", new ArrayList<>());
- Mockito.when(capabiltyRequirementConvertor.getOriginComponent(any(Map.class),
+ when(capabilityRequirementConverter.getOriginComponent(any(Map.class),
any(ComponentInstance.class))).thenReturn(Either.left(component));
- Mockito.when(capabiltyRequirementConvertor.convertComponentInstanceCapabilities(
+ when(capabilityRequirementConverter.convertComponentInstanceCapabilities(
any(ComponentInstance.class), any(Map.class), any(ToscaNodeTemplate.class)))
.thenReturn(Either.left(new ToscaNodeTemplate()));
@@ -733,10 +732,10 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentCache.put("uid", component);
- Mockito.when(capabiltyRequirementConvertor.getOriginComponent(any(Map.class),
+ when(capabilityRequirementConverter.getOriginComponent(any(Map.class),
any(ComponentInstance.class))).thenReturn(Either.left(component));
- Mockito.when(capabiltyRequirementConvertor.convertComponentInstanceCapabilities(
+ when(capabilityRequirementConverter.convertComponentInstanceCapabilities(
any(ComponentInstance.class), any(Map.class), any(ToscaNodeTemplate.class)))
.thenReturn(Either.right(ToscaError.GENERAL_ERROR));
@@ -779,7 +778,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentCache.put("uid", component);
- Mockito.when(capabiltyRequirementConvertor.getOriginComponent(any(Map.class),
+ when(capabilityRequirementConverter.getOriginComponent(any(Map.class),
any(ComponentInstance.class))).thenReturn(Either.right(false));
// default test
@@ -821,7 +820,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
component.setComponentInstancesInputs(componentInstancesInputs);
component.setComponentInstances(componentInstances);
- Mockito.when(capabiltyRequirementConvertor.getOriginComponent(any(Map.class),
+ when(capabilityRequirementConverter.getOriginComponent(any(Map.class),
any(ComponentInstance.class))).thenReturn(Either.left(component));
// default test
@@ -918,7 +917,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstances.add(instance);
container.setComponentInstances(componentInstances);
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
+ when(toscaOperationFacade.getToscaElement(any(String.class),
any(ComponentParametersView.class)))
.thenReturn(Either.right(StorageOperationStatus.BAD_REQUEST));
result = Deencapsulation.invoke(testSubject, "createProxyInterfaceTypes", container);
@@ -937,10 +936,10 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstances.add(instance);
container.setComponentInstances(componentInstances);
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
+ when(toscaOperationFacade.getToscaElement(any(String.class),
any(ComponentParametersView.class)))
.thenReturn(Either.left(new Resource()));
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.right(StorageOperationStatus.BAD_REQUEST));
result = Deencapsulation.invoke(testSubject, "createProxyInterfaceTypes", container);
Assert.assertTrue(result.isRight());
@@ -958,14 +957,14 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstances.add(instance);
container.setComponentInstances(componentInstances);
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
Component proxyResource = new Resource();
Map<String, InterfaceDefinition> proxyInterfaces = new HashMap<>();
proxyInterfaces.put("Local", new InterfaceDefinition("Local", "desc", new HashMap<>()));
proxyResource.setInterfaces(proxyInterfaces);
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
+ when(toscaOperationFacade.getToscaElement(any(String.class),
any(ComponentParametersView.class)))
.thenReturn(Either.left(proxyResource));
@@ -988,18 +987,18 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstances.add(instance);
container.setComponentInstances(componentInstances);
- Mockito.when(toscaOperationFacade.getLatestByName("serviceProxy"))
+ when(toscaOperationFacade.getLatestByName("serviceProxy"))
.thenReturn(Either.right(StorageOperationStatus.BAD_REQUEST));
// test when getLatestByName return is right
result = Deencapsulation.invoke(testSubject, "createProxyNodeTypes", componentCache, container);
Assert.assertNotNull(result);
}
-
+
@Test
public void testCreateServiceSubstitutionNodeTypes() throws Exception {
Map<String, Component> componentCache = new HashMap<>();
-
+
Component referencedService = getNewService();
referencedService.setInvariantUUID("uuid");
referencedService.setUUID("uuid");
@@ -1015,11 +1014,11 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstances.add(instance);
containerService.setComponentInstances(componentInstances);
-
- Mockito.when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
+
+ when(interfaceLifecycleOperation.getAllInterfaceLifecycleTypes())
.thenReturn(Either.left(Collections.emptyMap()));
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
- Mockito.when(capabiltyRequirementConvertor.convertRequirements(any(Map.class), any(Service.class),
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(capabilityRequirementConverter.convertRequirements(any(Map.class), any(Service.class),
any(ToscaNodeType.class))).thenReturn(Either.left(new ToscaNodeType()));
ToscaTemplate toscaNode = new ToscaTemplate("1_1");
@@ -1041,17 +1040,17 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
componentInstances.add(instance);
container.setComponentInstances(componentInstances);
- Mockito.when(toscaOperationFacade.getLatestByName("serviceProxy")).thenReturn(Either.left(new Resource()));
+ when(toscaOperationFacade.getLatestByName("serviceProxy")).thenReturn(Either.left(new Resource()));
ComponentParametersView parameterView = new ComponentParametersView();
parameterView.disableAll();
parameterView.setIgnoreCategories(false);
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
+ when(toscaOperationFacade.getToscaElement(any(String.class),
any(ComponentParametersView.class)))
.thenReturn(Either.right(StorageOperationStatus.BAD_REQUEST));
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
// test when getLatestByName is left
result = Deencapsulation.invoke(testSubject, "createProxyNodeTypes", componentCache, container);
@@ -1066,7 +1065,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
ComponentInstance instance = new ComponentInstance();
ToscaNodeType result;
- Mockito.when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
+ when(dataTypeCache.getAll()).thenReturn(Either.left(new HashMap<>()));
// default test
result = Deencapsulation.invoke(testSubject, "createProxyNodeType", componentCache, origComponent,
@@ -1111,138 +1110,185 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
}
@Test
- public void testAddRequirement() throws Exception {
- ComponentInstance fromInstance = new ComponentInstance();
- Component fromOriginComponent = new Resource();
- List<ComponentInstance> instancesList = new ArrayList<>();
- RequirementCapabilityRelDef rel = new RequirementCapabilityRelDef();
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
- Map<String, Component> componentCache = new HashMap<>();
- boolean result;
-
- List<CapabilityRequirementRelationship> relationships = new ArrayList<>();
- CapabilityRequirementRelationship cap = new CapabilityRequirementRelationship();
- cap.setRequirement(new RequirementDataDefinition());
- RelationshipInfo relation = new RelationshipInfo();
- relation.setRequirementUid("Uid");
- relation.setRequirement("requirment");
- relation.setCapability("cap");
- relation.setCapabilityOwnerId("id1");
- cap.setRelation(relation);
- relationships.add(cap);
- rel.setRelationships(relationships);
- rel.setToNode("name");
- fromInstance.setUniqueId("name");
- fromInstance.setComponentUid("string");
+ public void buildRequirementFailure() {
+ final Component fromOriginComponent = new Resource();
+ final ComponentInstance fromInstance = new ComponentInstance();
+ final String fromInstanceUid = "fromInstanceUid";
+ fromInstance.setUniqueId(fromInstanceUid);
+ fromInstance.setComponentUid("componentUid");
+ final RequirementCapabilityRelDef relationshipDefinition = new RequirementCapabilityRelDef();
+ relationshipDefinition.setToNode("wrongNodeUid");
+ final List<CapabilityRequirementRelationship> relationshipList = new ArrayList<>();
+ final CapabilityRequirementRelationship relationship = new CapabilityRequirementRelationship();
+ relationship.setRequirement(new RequirementDataDefinition());
+ relationshipList.add(relationship);
+ relationshipDefinition.setRelationships(relationshipList);
+ final List<ComponentInstance> instancesList = new ArrayList<>();
instancesList.add(fromInstance);
- Map<String, List<RequirementDefinition>> requirements = new HashMap<>();
- fromOriginComponent.setRequirements(requirements);
-
- // default test
- result = Deencapsulation.invoke(testSubject, "addRequirement", fromInstance, fromOriginComponent, instancesList,
- rel, toscaRequirements, componentCache);
- Assert.assertNotNull(result);
+ String expectedError = String
+ .format("Failed to find a relation from the node %s to the node %s", fromInstance.getName(),
+ relationshipDefinition.getToNode());
+ assertThrows(ToscaExportException.class, () ->
+ Deencapsulation.invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent,
+ instancesList, relationshipDefinition, new HashMap<>()), expectedError);
+
+ try {
+ Deencapsulation.invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent,
+ instancesList, relationshipDefinition, new HashMap<>());
+ } catch (Exception e) {
+ assertTrue(e instanceof ToscaExportException);
+ assertEquals(expectedError, e.getMessage());
+ }
+
+ final RelationshipInfo relation = new RelationshipInfo();
+ final String requirementUid = "Uid";
+ relation.setRequirementUid(requirementUid);
+ final String requirementName = "requirementName";
+ relation.setRequirement(requirementName);
+ final String capabilityName = "capabilityName";
+ relation.setCapability(capabilityName);
+ final String capabilityOwnerId = "capabilityOwnerId";
+ relation.setCapabilityOwnerId(capabilityOwnerId);
+ relationship.setRelation(relation);
+
+ final Map<String, List<RequirementDefinition>> requirementMap = new HashMap<>();
+ final RequirementDefinition requirementDefinition = new RequirementDefinition();
+ requirementMap.put(requirementUid, Collections.singletonList(requirementDefinition));
+ fromOriginComponent.setRequirements(requirementMap);
+ relationshipDefinition.setToNode(fromInstanceUid);
+
+ expectedError = String
+ .format("Failed to find a requirement with uniqueId %s on a component with uniqueId %s",
+ relation.getRequirementUid(), fromOriginComponent.getUniqueId());
+
+
+ assertThrows(ToscaExportException.class, () ->
+ Deencapsulation.invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent,
+ instancesList, relationshipDefinition, new HashMap<>()), expectedError);
+
+ requirementDefinition.setName(requirementName);
+
+ when(toscaOperationFacade.getToscaElement(any(String.class), any(ComponentParametersView.class)))
+ .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+
+ expectedError = String.format(
+ "Failed to build substituted name for the requirement %s. "
+ + "Failed to get an origin component with uniqueId %s",
+ requirementName, fromInstance.getActualComponentUid());
+ assertThrows(ToscaExportException.class, () -> Deencapsulation
+ .invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent, instancesList,
+ relationshipDefinition, new HashMap<>()), expectedError);
+
+ final Component toOriginComponent = new Resource();
+ final Map<String, List<CapabilityDefinition>> capabilityMap = new HashMap<>();
+ final CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
+
+ capabilityDefinition.setName(capabilityName);
+ capabilityDefinition.setOwnerId(capabilityOwnerId);
+ capabilityDefinition.setType("aType");
+ final String capabilityPreviousName = "capabilityPreviousName";
+ capabilityDefinition.setPreviousName(capabilityPreviousName);
+ capabilityMap.put(capabilityName, Collections.singletonList(capabilityDefinition));
+ toOriginComponent.setCapabilities(capabilityMap);
+ when(toscaOperationFacade.getToscaElement(any(String.class), any(ComponentParametersView.class)))
+ .thenReturn(Either.left(toOriginComponent));
+
+
+ requirementDefinition.setCapability(capabilityName);
+ relation.setCapability("wrong");
+ final String requirementPreviousName = "requirementPreviousName";
+ requirementDefinition.setPreviousName(requirementPreviousName);
+ requirementDefinition.setPath(new ArrayList<>());
+
+ expectedError = String
+ .format("Failed to find a capability with name %s on a component with uniqueId %s",
+ relation.getCapability(), fromOriginComponent.getUniqueId());
+
+ assertThrows(ToscaExportException.class, () -> Deencapsulation
+ .invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent, instancesList,
+ relationshipDefinition, new HashMap<>()),
+ expectedError);
}
@Test
- public void testAddRequirmentsWhenFindRequirmentsReturnsValue() {
-
- ComponentInstance fromInstance = new ComponentInstance();
- Component fromOriginComponent = new Resource();
- List<ComponentInstance> instancesList = new ArrayList<>();
- RequirementCapabilityRelDef rel = new RequirementCapabilityRelDef();
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
- Map<String, Component> componentCache = new HashMap<>();
- boolean result;
-
- List<CapabilityRequirementRelationship> relationships = new ArrayList<>();
- CapabilityRequirementRelationship cap = new CapabilityRequirementRelationship();
- cap.setRequirement(new RequirementDataDefinition());
- RelationshipInfo relation = new RelationshipInfo();
- relation.setRequirementUid("Uid");
- relation.setRequirement("requirment");
- relation.setCapability("cap");
- relation.setCapabilityOwnerId("id1");
- cap.setRelation(relation);
- relationships.add(cap);
- rel.setRelationships(relationships);
- rel.setToNode("name");
+ public void testBuildRequirement() {
+ final ComponentInstance fromInstance = new ComponentInstance();
fromInstance.setUniqueId("name");
fromInstance.setComponentUid("string");
+ final List<ComponentInstance> instancesList = new ArrayList<>();
+
+ final Map<String, Component> componentCache = new HashMap<>();
+ final List<CapabilityRequirementRelationship> relationshipList = new ArrayList<>();
+ final CapabilityRequirementRelationship relationship = new CapabilityRequirementRelationship();
+ relationship.setRequirement(new RequirementDataDefinition());
+ final RelationshipInfo relation = new RelationshipInfo();
+ final String requirementUid = "Uid";
+ relation.setRequirementUid(requirementUid);
+ final String requirementName = "requirementName";
+ relation.setRequirement(requirementName);
+ final String capabilityName = "capabilityName";
+ relation.setCapability(capabilityName);
+ final String capabilityOwnerId = "capabilityOwnerId";
+ relation.setCapabilityOwnerId(capabilityOwnerId);
+ relationship.setRelation(relation);
+ relationshipList.add(relationship);
+ final RequirementCapabilityRelDef relationshipDefinition = new RequirementCapabilityRelDef();
+ relationshipDefinition.setRelationships(relationshipList);
+ relationshipDefinition.setToNode("name");
instancesList.add(fromInstance);
- Map<String, List<RequirementDefinition>> requirements = new HashMap<>();
-
- List<RequirementDefinition> defs = new ArrayList<>();
- RequirementDefinition def = new RequirementDefinition();
- def.setName("requirment");
- def.setCapability("cap");
- defs.add(def);
- requirements.put("key", defs);
- fromOriginComponent.setRequirements(requirements);
-
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
- any(ComponentParametersView.class)))
- .thenReturn(Either.right(StorageOperationStatus.BAD_REQUEST));
-
- // default test
- result = Deencapsulation.invoke(testSubject, "addRequirement", fromInstance, fromOriginComponent, instancesList,
- rel, toscaRequirements, componentCache);
- Assert.assertNotNull(result);
- }
-
- @Test
- public void testAddRequirmentsWhenCapabilityBelongsToRelation() {
- ComponentInstance fromInstance = new ComponentInstance();
- Component fromOriginComponent = new Resource();
- List<ComponentInstance> instancesList = new ArrayList<>();
- RequirementCapabilityRelDef rel = new RequirementCapabilityRelDef();
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
- Map<String, Component> componentCache = new HashMap<>();
- boolean result;
-
- List<CapabilityRequirementRelationship> relationships = new ArrayList<>();
- CapabilityRequirementRelationship cap = new CapabilityRequirementRelationship();
- cap.setRequirement(new RequirementDataDefinition());
- RelationshipInfo relation = new RelationshipInfo();
- relation.setRequirementUid("Uid");
- relation.setRequirement("requirment");
- relation.setCapability("cap");
- relation.setCapabilityOwnerId("id1");
- cap.setRelation(relation);
- relationships.add(cap);
- rel.setRelationships(relationships);
- rel.setToNode("name");
- fromInstance.setUniqueId("name");
- fromInstance.setComponentUid("string");
- instancesList.add(fromInstance);
- Map<String, List<RequirementDefinition>> requirements = new HashMap<>();
-
- List<RequirementDefinition> defs = new ArrayList<>();
- RequirementDefinition def = new RequirementDefinition();
- def.setName("requirment");
- def.setCapability("cap");
- defs.add(def);
- requirements.put("key", defs);
- fromOriginComponent.setRequirements(requirements);
-
- Map<String, List<CapabilityDefinition>> capabilities = new HashMap<>();
- List<CapabilityDefinition> caps = new ArrayList<>();
- CapabilityDefinition capdef = new CapabilityDefinition();
- capdef.setOwnerId("id");
- capdef.setName("name");
- capdef.setType("type");
- caps.add(capdef);
- capabilities.put("cap", caps);
-
- fromOriginComponent.setCapabilities(capabilities);
-
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
- any(ComponentParametersView.class))).thenReturn(Either.left(fromOriginComponent));
-
- // default test
- result = Deencapsulation.invoke(testSubject, "addRequirement", fromInstance, fromOriginComponent, instancesList,
- rel, toscaRequirements, componentCache);
- Assert.assertNotNull(result);
+ final RequirementDefinition requirementDefinition = new RequirementDefinition();
+ requirementDefinition.setName(requirementName);
+ requirementDefinition.setCapability(capabilityName);
+ final String requirementPreviousName = "requirementPreviousName";
+ requirementDefinition.setPreviousName(requirementPreviousName);
+ requirementDefinition.setPath(new ArrayList<>());
+ final Map<String, List<RequirementDefinition>> requirementMap = new HashMap<>();
+ requirementMap.put(requirementUid, Collections.singletonList(requirementDefinition));
+ final Component fromOriginComponent = new Resource();
+ fromOriginComponent.setRequirements(requirementMap);
+
+ final Map<String, List<CapabilityDefinition>> capabilityMap = new HashMap<>();
+ final CapabilityDefinition capabilityDefinition = new CapabilityDefinition();
+ capabilityDefinition.setName(capabilityName);
+ capabilityDefinition.setOwnerId(capabilityOwnerId);
+ final String capabilityPreviousName = "capabilityPreviousName";
+ capabilityDefinition.setPreviousName(capabilityPreviousName);
+ capabilityMap.put(capabilityName, Collections.singletonList(capabilityDefinition));
+ final Component toOriginComponent = new Resource();
+ toOriginComponent.setCapabilities(capabilityMap);
+
+ when(toscaOperationFacade.getToscaElement(any(String.class), any(ComponentParametersView.class)))
+ .thenReturn(Either.left(toOriginComponent));
+ final String builtCapabilityName = "builtCapabilityName";
+ when(
+ capabilityRequirementConverter
+ .buildSubstitutedName(anyMap(), eq(toOriginComponent), anyList(), eq(capabilityName), eq(
+ capabilityPreviousName)))
+ .thenReturn(Either.left(builtCapabilityName));
+
+ final String builtRequirementName = "builtRequirementName";
+ when(
+ capabilityRequirementConverter
+ .buildSubstitutedName(anyMap(), eq(fromOriginComponent), anyList(), eq(requirementName), eq(
+ requirementPreviousName)))
+ .thenReturn(Either.left(builtRequirementName));
+
+ final Map<String, ToscaTemplateRequirement> actualRequirementMap =
+ Deencapsulation.invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent,
+ instancesList, relationshipDefinition, componentCache);
+ assertNotNull(actualRequirementMap);
+ assertFalse(actualRequirementMap.isEmpty());
+ assertTrue(actualRequirementMap.containsKey(builtRequirementName));
+ final ToscaTemplateRequirement actualToscaTemplateRequirement = actualRequirementMap.get(builtRequirementName);
+ assertNotNull(actualToscaTemplateRequirement);
+ assertEquals(builtCapabilityName, actualToscaTemplateRequirement.getCapability());
+
+ //to toOriginComponent not found
+ when(toscaOperationFacade.getToscaElement(any(String.class), any(ComponentParametersView.class)))
+ .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
+
+ assertThrows(ToscaExportException.class, () -> Deencapsulation.invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent,
+ instancesList, relationshipDefinition, componentCache));
}
@Test
@@ -1253,7 +1299,6 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
RequirementCapabilityRelDef rel = new RequirementCapabilityRelDef();
List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
Map<String, Component> componentCache = new HashMap<>();
- boolean result;
List<CapabilityRequirementRelationship> relationships = new ArrayList<>();
CapabilityRequirementRelationship cap = new CapabilityRequirementRelationship();
@@ -1291,23 +1336,26 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
capabilities.put("cap", caps);
fromOriginComponent.setCapabilities(capabilities);
- Mockito.when(toscaOperationFacade.getToscaElement(any(String.class),
+ when(toscaOperationFacade.getToscaElement(any(String.class),
any(ComponentParametersView.class))).thenReturn(Either.left(fromOriginComponent));
- Mockito.when(
- capabiltyRequirementConvertor
+ when(
+ capabilityRequirementConverter
.buildSubstitutedName(anyMap(), any(Component.class), anyList(), anyString(), anyString()))
.thenReturn(Either.right(false));
- // default test
- result = Deencapsulation.invoke(testSubject, "addRequirement", fromInstance, fromOriginComponent, instancesList,
- rel, toscaRequirements, componentCache);
- Assert.assertNotNull(result);
+ final String expectedErrorMsg =
+ String.format("Failed to build a substituted capability name for the capability "
+ + "with name %s on a component with uniqueId %s",
+ cap.getRequirement(), fromOriginComponent.getUniqueId());
+
+ assertThrows(ToscaExportException.class, () ->
+ Deencapsulation.invoke(testSubject, "buildRequirement", fromInstance, fromOriginComponent, instancesList,
+ rel, componentCache), expectedErrorMsg);
}
@Test
- public void testBuildAndAddRequirement() throws Exception {
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
+ public void testBuildAndAddRequirement() {
Component fromOriginComponent = new Resource();
Component toOriginComponent = new Resource();
CapabilityDefinition capability = new CapabilityDefinition();
@@ -1315,7 +1363,8 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
RelationshipInfo reqAndRelationshipPair = new RelationshipInfo();
ComponentInstance toInstance = new ComponentInstance();
Map<String, Component> componentCache = new HashMap<>();
- boolean result;
+ final CapabilityRequirementRelationship capabilityRequirementRelationship = new CapabilityRequirementRelationship();
+ capabilityRequirementRelationship.setRelation(reqAndRelationshipPair);
capability.setPath(new ArrayList<>());
capability.setPreviousName("before cap");
reqAndRelationshipPair.setCapability("cap");
@@ -1323,46 +1372,57 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
requirement.setPreviousName("before req");
reqAndRelationshipPair.setRequirement("req");
- Mockito.when(
- capabiltyRequirementConvertor
+ when(
+ capabilityRequirementConverter
.buildSubstitutedName(anyMap(), eq(toOriginComponent), anyList(), eq("cap"), anyString()))
.thenReturn(Either.left("buildCapNameRes"));
- Mockito.when(
- capabiltyRequirementConvertor
+ when(
+ capabilityRequirementConverter
.buildSubstitutedName(anyMap(), eq(fromOriginComponent), anyList(), eq("req"), anyString()))
- .thenReturn(Either.right(false));
+ .thenReturn(Either.left("buildReqNameRes"));
// default test
- result = Deencapsulation.invoke(testSubject, "buildAndAddRequirement", toscaRequirements, fromOriginComponent,
- toOriginComponent, capability, requirement, reqAndRelationshipPair, toInstance, componentCache);
- Assert.assertNotNull(result);
+ final Map<String, ToscaTemplateRequirement> requirementMap =
+ Deencapsulation.invoke(testSubject, "buildRequirement", fromOriginComponent, toOriginComponent,
+ capability, requirement, capabilityRequirementRelationship, toInstance, componentCache);
+ assertNotNull(requirementMap);
+ assertFalse(requirementMap.isEmpty());
+ assertTrue(requirementMap.containsKey("buildReqNameRes"));
+ final ToscaTemplateRequirement actualToscaTemplateRequirement = requirementMap.get("buildReqNameRes");
+ assertNotNull(actualToscaTemplateRequirement);
+ assertEquals("buildCapNameRes", actualToscaTemplateRequirement.getCapability());
}
@Test
- public void testBuildAndAddRequirementBuildSubtitutedNameReturnsValueTwice() {
- List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
- Component fromOriginComponent = new Resource();
- Component toOriginComponent = new Resource();
- CapabilityDefinition capability = new CapabilityDefinition();
- RequirementDefinition requirement = new RequirementDefinition();
- RelationshipInfo reqAndRelationshipPair = new RelationshipInfo();
+ public void testBuildRequirementBuildSubstitutedNameReturnsValueTwice() {
+ final Component fromOriginComponent = new Resource();
+ final Component toOriginComponent = new Resource();
+ final CapabilityDefinition capability = new CapabilityDefinition();
+ final RequirementDefinition requirement = new RequirementDefinition();
+ final RelationshipInfo relationship = new RelationshipInfo();
+ final CapabilityRequirementRelationship capabilityRequirementRelationship = new CapabilityRequirementRelationship();
+ capabilityRequirementRelationship.setRelation(relationship);
ComponentInstance toInstance = new ComponentInstance();
Map<String, Component> componentCache = new HashMap<>();
- boolean result;
capability.setPath(new ArrayList<>());
- reqAndRelationshipPair.setCapability("cap");
+ relationship.setCapability("cap");
requirement.setPath(new ArrayList<>());
- reqAndRelationshipPair.setRequirement("req");
-
- Mockito.when(capabiltyRequirementConvertor.buildSubstitutedName(any(), any(), any(), any(), any()))
- .thenReturn(Either.left("buildCapNameRes"));
-
- // default test
- result = Deencapsulation.invoke(testSubject, "buildAndAddRequirement", toscaRequirements, fromOriginComponent,
- toOriginComponent, capability, requirement, reqAndRelationshipPair, toInstance, componentCache);
- Assert.assertNotNull(result);
- Assert.assertTrue(result);
+ relationship.setRequirement("req");
+
+ final String builtCapabilityOrRequirementName = "builtCapabilityOrRequirementName";
+ when(capabilityRequirementConverter.buildSubstitutedName(any(), any(), any(), any(), any()))
+ .thenReturn(Either.left(builtCapabilityOrRequirementName));
+
+ final Map<String, ToscaTemplateRequirement> requirementMap = Deencapsulation
+ .invoke(testSubject, "buildRequirement", fromOriginComponent, toOriginComponent, capability, requirement,
+ capabilityRequirementRelationship, toInstance, componentCache);
+ assertNotNull(requirementMap);
+ assertFalse(requirementMap.isEmpty());
+ assertTrue(requirementMap.containsKey(builtCapabilityOrRequirementName));
+ final ToscaTemplateRequirement actualToscaTemplateRequirement = requirementMap.get(builtCapabilityOrRequirementName);
+ assertNotNull(actualToscaTemplateRequirement);
+ assertEquals(builtCapabilityOrRequirementName, actualToscaTemplateRequirement.getCapability());
}
@Test
@@ -1435,7 +1495,7 @@ public class ToscaExportHandlerTest extends BeConfDependentTest {
Map<String, Component> componentCache = new HashMap<>();
Either<SubstitutionMapping, ToscaError> result;
- Mockito.when(capabiltyRequirementConvertor.convertSubstitutionMappingCapabilities(componentCache, component))
+ when(capabilityRequirementConverter.convertSubstitutionMappingCapabilities(componentCache, component))
.thenReturn(Either.right(ToscaError.NODE_TYPE_CAPABILITY_ERROR));
// default test return isRight
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandlerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandlerTest.java
new file mode 100644
index 0000000000..3225999974
--- /dev/null
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportRelationshipTemplatesHandlerTest.java
@@ -0,0 +1,111 @@
+/*
+ * ============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.tosca;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
+import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationship;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationshipTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement;
+
+class ToscaExportRelationshipTemplatesHandlerTest {
+
+ @Test
+ void testCreateFromEmptyNodeTemplateMapReturnsEmptyMap() {
+ final Map<String, ToscaRelationshipTemplate> actualRelationshipTemplateMap =
+ new ToscaExportRelationshipTemplatesHandler().createFrom(Collections.emptyMap());
+ assertNotNull(actualRelationshipTemplateMap);
+ assertTrue(actualRelationshipTemplateMap.isEmpty());
+ }
+
+ @Test
+ void testCreateFromSuccess() {
+ final Map<String, ToscaNodeTemplate> nodeTemplateMap = new HashMap<>();
+
+ final ToscaNodeTemplate nodeTemplateWithNoRequirements = new ToscaNodeTemplate();
+ nodeTemplateMap.put("nodeTemplateWithNoRequirements", nodeTemplateWithNoRequirements);
+
+ final ToscaNodeTemplate nodeTemplateWithRequirements = new ToscaNodeTemplate();
+ final List<Map<String, ToscaTemplateRequirement>> requirements = new ArrayList<>();
+
+ final Map<String, ToscaTemplateRequirement> requirementMap = new HashMap<>();
+ final ToscaTemplateRequirement complexRequirement = new ToscaTemplateRequirement();
+ complexRequirement.setNode("aNode");
+
+ final ToscaRelationship toscaRelationship = new ToscaRelationship();
+ final String relationshipType = "tosca.relationships.ConnectsTo";
+ toscaRelationship.setType(relationshipType);
+
+ final Map<String, ToscaInterfaceDefinition> interfaces = new HashMap<>();
+ final ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition();
+ final String interfaceConfigureType = "tosca.interfaces.relationship.Configure";
+ toscaInterfaceDefinition.setType(interfaceConfigureType);
+ final HashMap<String, Object> operationMap = new HashMap<>();
+ final String preConfigSourceOperationType = "pre_configure_source";
+ operationMap.put(preConfigSourceOperationType, new Object());
+ toscaInterfaceDefinition.setOperations(operationMap);
+
+ interfaces.put(interfaceConfigureType, toscaInterfaceDefinition);
+ toscaRelationship.setInterfaces(interfaces);
+ complexRequirement.setRelationship(toscaRelationship);
+ requirementMap.put("requirement1", complexRequirement);
+
+ final ToscaTemplateRequirement simpleRequirement = new ToscaTemplateRequirement();
+ simpleRequirement.setNode("anotherNode");
+ simpleRequirement.setRelationship("aRelationship");
+ requirementMap.put("requirement2", simpleRequirement);
+
+ requirements.add(requirementMap);
+ nodeTemplateWithRequirements.setRequirements(requirements);
+ nodeTemplateMap.put("nodeTemplateWithRequirements", nodeTemplateWithRequirements);
+
+ final Map<String, ToscaRelationshipTemplate> actualRelationshipTemplateMap =
+ new ToscaExportRelationshipTemplatesHandler().createFrom(nodeTemplateMap);
+
+ assertNotNull(actualRelationshipTemplateMap);
+ assertEquals(1, actualRelationshipTemplateMap.size());
+ final ToscaRelationshipTemplate actualRelationshipTemplate = actualRelationshipTemplateMap.values().iterator().next();
+ assertEquals(relationshipType, actualRelationshipTemplate.getType());
+
+ final Map<String, ToscaInterfaceDefinition> actualInterfaceMap = actualRelationshipTemplate.getInterfaces();
+ assertNotNull(actualInterfaceMap);
+ assertEquals(1, actualInterfaceMap.size());
+ assertTrue(actualInterfaceMap.containsKey(interfaceConfigureType));
+
+ final ToscaInterfaceDefinition actualToscaInterfaceDefinition =
+ actualInterfaceMap.get(interfaceConfigureType);
+ assertEquals(toscaInterfaceDefinition.getType(), actualToscaInterfaceDefinition.getType());
+
+ final Map<String, Object> actualOperationMap = actualToscaInterfaceDefinition.getOperations();
+ assertNotNull(actualOperationMap);
+ assertEquals(1, actualOperationMap.size());
+ assertTrue(actualOperationMap.containsKey(preConfigSourceOperationType));
+ }
+} \ No newline at end of file
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilderTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilderTest.java
new file mode 100644
index 0000000000..cee70661be
--- /dev/null
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/builder/ToscaRelationshipBuilderTest.java
@@ -0,0 +1,122 @@
+/*
+ * ============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.tosca.builder;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.model.CapabilityRequirementRelationship;
+import org.openecomp.sdc.be.model.RelationshipImpl;
+import org.openecomp.sdc.be.model.RelationshipInfo;
+import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
+import org.openecomp.sdc.be.tosca.model.ToscaOperationAssignment;
+import org.openecomp.sdc.be.tosca.model.ToscaPropertyAssignment;
+import org.openecomp.sdc.be.tosca.model.ToscaRelationship;
+import org.openecomp.sdc.be.ui.model.OperationUi;
+import org.openecomp.sdc.be.ui.model.PropertyAssignmentUi;
+
+class ToscaRelationshipBuilderTest {
+
+ @Test
+ void testBuildFromCapabilityRequirementRelationshipSuccess() {
+ final CapabilityRequirementRelationship relationship = new CapabilityRequirementRelationship();
+ final RelationshipImpl relationshipImpl = new RelationshipImpl();
+ final String relationshipType = "relationshipType";
+ relationshipImpl.setType(relationshipType);
+ final RelationshipInfo relationshipInfo = new RelationshipInfo();
+ relationshipInfo.setRelationships(relationshipImpl);
+ relationship.setRelation(relationshipInfo);
+
+ final List<OperationUi> operationList = new ArrayList<>();
+ final OperationUi operationUi1 = new OperationUi();
+ operationUi1.setInterfaceType("interfaceType1");
+ operationUi1.setOperationType("operation1");
+ operationUi1.setImplementation("implementation");
+ operationList.add(operationUi1);
+
+ final OperationUi operationUi2 = new OperationUi();
+ operationUi2.setInterfaceType("interfaceType1");
+ operationUi2.setOperationType("operation2");
+ operationUi2.setImplementation("implementation");
+ operationList.add(operationUi2);
+ final List<PropertyAssignmentUi> operation2InputList = new ArrayList<>();
+ final PropertyAssignmentUi propertyAssignmentUi1 = new PropertyAssignmentUi();
+ propertyAssignmentUi1.setValue("propertyAssignmentUi1Value");
+ propertyAssignmentUi1.setType("string");
+ propertyAssignmentUi1.setName("propertyAssignmentUi1");
+ operation2InputList.add(propertyAssignmentUi1);
+ final PropertyAssignmentUi propertyAssignmentUi2 = new PropertyAssignmentUi();
+ propertyAssignmentUi2.setValue("propertyAssignmentUi2Value");
+ propertyAssignmentUi2.setType("string");
+ propertyAssignmentUi2.setName("propertyAssignmentUi2");
+ operation2InputList.add(propertyAssignmentUi2);
+ operationUi2.setInputs(operation2InputList);
+
+ final OperationUi operationUi3 = new OperationUi();
+ operationUi3.setInterfaceType("interfaceType2");
+ operationUi3.setOperationType("operation1");
+ operationUi3.setImplementation("implementation");
+ operationList.add(operationUi3);
+
+ relationship.setOperations(operationList);
+
+
+ final ToscaRelationship toscaRelationship = new ToscaRelationshipBuilder().from(relationship);
+ assertEquals(toscaRelationship.getType(), relationshipType);
+ final Map<String, ToscaInterfaceDefinition> interfaceMap = toscaRelationship.getInterfaces();
+ assertNotNull(interfaceMap);
+ assertFalse(interfaceMap.isEmpty());
+ assertEquals(2, interfaceMap.size());
+ final ToscaInterfaceDefinition toscaInterfaceDefinition = interfaceMap.get(operationUi1.getInterfaceType());
+ assertNull(toscaInterfaceDefinition.getType());
+ assertNotNull(toscaInterfaceDefinition.getOperations());
+ assertEquals(2, toscaInterfaceDefinition.getOperations().size());
+ final Object actualOperation1Obj = toscaInterfaceDefinition.getOperations().get(operationUi1.getOperationType());
+ assertTrue(actualOperation1Obj instanceof ToscaOperationAssignment);
+ final ToscaOperationAssignment actualOperation1 = (ToscaOperationAssignment) actualOperation1Obj;
+ assertOperationUi(actualOperation1, operationUi1);
+ }
+
+ private void assertOperationUi(final ToscaOperationAssignment toscaOperationAssignment, final OperationUi operationUi1) {
+ if (operationUi1 == null) {
+ assertNull(toscaOperationAssignment);
+ return;
+ }
+ assertEquals(toscaOperationAssignment.getImplementation(), operationUi1.getImplementation());
+ if (operationUi1.getInputs() == null) {
+ assertNull(toscaOperationAssignment.getInputs());
+ return;
+ }
+ assertEquals(toscaOperationAssignment.getInputs().size(), operationUi1.getInputs().size());
+ operationUi1.getInputs().forEach(propertyAssignmentUi -> {
+ final ToscaPropertyAssignment toscaPropertyAssignment = toscaOperationAssignment.getInputs()
+ .get(propertyAssignmentUi.getName());
+ assertNotNull(toscaPropertyAssignment);
+ assertEquals(propertyAssignmentUi.getValue(), toscaPropertyAssignment.getValue());
+ });
+ }
+} \ No newline at end of file
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaRequirementTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaRequirementTest.java
deleted file mode 100644
index bb3af40e36..0000000000
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaRequirementTest.java
+++ /dev/null
@@ -1,67 +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.tosca.model;
-
-import org.junit.Test;
-
-import java.util.List;
-import java.util.Map;
-
-
-public class ToscaRequirementTest {
-
- private ToscaRequirement createTestSubject() {
- return new ToscaRequirement();
- }
-
-
- @Test
- public void testGetOccurrences() throws Exception {
- ToscaRequirement testSubject;
- List<Object> result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getOccurrences();
- }
-
-
- @Test
- public void testSetOccurrences() throws Exception {
- ToscaRequirement testSubject;
- List<Object> occurrences = null;
-
- // default test
- testSubject = createTestSubject();
- testSubject.setOccurrences(occurrences);
- }
-
-
- @Test
- public void testToMap() throws Exception {
- ToscaRequirement testSubject;
- Map<String, Object> result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.toMap();
- }
-}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirementTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirementTest.java
index 5d45407843..bb5a3e50f0 100644
--- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirementTest.java
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/model/ToscaTemplateRequirementTest.java
@@ -7,9 +7,9 @@
* 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.
@@ -20,91 +20,60 @@
package org.openecomp.sdc.be.tosca.model;
-import org.junit.Test;
-
-import java.util.Map;
-
-
-public class ToscaTemplateRequirementTest {
-
- private ToscaTemplateRequirement createTestSubject() {
- return new ToscaTemplateRequirement();
- }
-
-
- @Test
- public void testGetCapability() throws Exception {
- ToscaTemplateRequirement testSubject;
- String result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getCapability();
- }
-
-
- @Test
- public void testSetCapability() throws Exception {
- ToscaTemplateRequirement testSubject;
- String capability = "";
-
- // default test
- testSubject = createTestSubject();
- testSubject.setCapability(capability);
- }
-
-
- @Test
- public void testGetNode() throws Exception {
- ToscaTemplateRequirement testSubject;
- String result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getNode();
- }
-
-
- @Test
- public void testSetNode() throws Exception {
- ToscaTemplateRequirement testSubject;
- String node = "";
-
- // default test
- testSubject = createTestSubject();
- testSubject.setNode(node);
- }
-
-
- @Test
- public void testGetRelationship() throws Exception {
- ToscaTemplateRequirement testSubject;
- String result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getRelationship();
- }
-
-
- @Test
- public void testSetRelationship() throws Exception {
- ToscaTemplateRequirement testSubject;
- String relationship = "";
-
- // default test
- testSubject = createTestSubject();
- testSubject.setRelationship(relationship);
- }
-
-
- @Test
- public void testToMap() throws Exception {
- ToscaTemplateRequirement testSubject;
- Map<String, Object> result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.toMap();
- }
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.exception.InvalidArgumentException;
+
+class ToscaTemplateRequirementTest {
+
+ @Test
+ void testSetRelationship() {
+ final ToscaTemplateRequirement toscaTemplateRequirement = new ToscaTemplateRequirement();
+ toscaTemplateRequirement.setRelationship(null);
+ assertNull(toscaTemplateRequirement.getRelationship());
+
+ final String relationshipType = "aType";
+ toscaTemplateRequirement.setRelationship(relationshipType);
+ Object actualRelationship = toscaTemplateRequirement.getRelationship();
+ assertEquals(relationshipType, actualRelationship);
+
+ final ToscaRelationship toscaRelationship = new ToscaRelationship();
+ toscaRelationship.setType(relationshipType);
+ toscaTemplateRequirement.setRelationship(toscaRelationship);
+ actualRelationship = toscaTemplateRequirement.getRelationship();
+ assertEquals(toscaRelationship, actualRelationship);
+
+ assertThrows(InvalidArgumentException.class, () -> toscaTemplateRequirement.setRelationship(1));
+ }
+
+ @Test
+ void testIsRelationshipComplexNotation() {
+ final ToscaTemplateRequirement toscaTemplateRequirement = new ToscaTemplateRequirement();
+ assertFalse(toscaTemplateRequirement.isRelationshipComplexNotation());
+ toscaTemplateRequirement.setRelationship("");
+ assertFalse(toscaTemplateRequirement.isRelationshipComplexNotation());
+ toscaTemplateRequirement.setRelationship(new ToscaRelationship());
+ assertTrue(toscaTemplateRequirement.isRelationshipComplexNotation());
+ }
+
+ @Test
+ void testGetRelationshipAsComplexType() {
+ final ToscaTemplateRequirement toscaTemplateRequirement = new ToscaTemplateRequirement();
+ ToscaRelationship actualRelationship = toscaTemplateRequirement.getRelationshipAsComplexType();
+ assertNull(actualRelationship);
+ final String relationshipType = "aType";
+ toscaTemplateRequirement.setRelationship(relationshipType);
+ actualRelationship = toscaTemplateRequirement.getRelationshipAsComplexType();
+ assertEquals(relationshipType, actualRelationship.getType());
+
+ final ToscaRelationship expectedRelationship = new ToscaRelationship();
+ toscaTemplateRequirement.setRelationship(expectedRelationship);
+ actualRelationship = toscaTemplateRequirement.getRelationshipAsComplexType();
+ assertEquals(expectedRelationship, actualRelationship);
+ }
}
diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtilTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtilTest.java
new file mode 100644
index 0000000000..8eebebe5cf
--- /dev/null
+++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/utils/InterfaceTypesNameUtilTest.java
@@ -0,0 +1,53 @@
+/*
+ * ============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.tosca.utils;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class InterfaceTypesNameUtilTest {
+
+ @Test
+ void testBuildInterfaceShortNameSuccess() {
+ String interfaceShortName = InterfaceTypesNameUtil.buildShortName("an.interface.name");
+ assertEquals("name", interfaceShortName);
+
+ interfaceShortName = InterfaceTypesNameUtil.buildShortName("name");
+ assertEquals("name", interfaceShortName);
+
+ interfaceShortName = InterfaceTypesNameUtil.buildShortName("");
+ assertEquals("", interfaceShortName);
+
+ interfaceShortName = InterfaceTypesNameUtil.buildShortName("an.");
+ assertEquals("an.", interfaceShortName);
+
+ interfaceShortName = InterfaceTypesNameUtil.buildShortName(".");
+ assertEquals(".", interfaceShortName);
+
+ interfaceShortName = InterfaceTypesNameUtil.buildShortName(".");
+ assertEquals(".", interfaceShortName);
+ }
+
+ @Test
+ void testBuildInterfaceShortNameNullArgument() {
+ assertThrows(IllegalArgumentException.class, () -> InterfaceTypesNameUtil.buildShortName(null));
+ }
+} \ No newline at end of file
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationship.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationship.java
index d25bd2fcf8..9eb0357a5c 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationship.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationship.java
@@ -20,33 +20,23 @@
package org.openecomp.sdc.be.model;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
+import org.openecomp.sdc.be.ui.model.OperationUi;
+
/**
* Contains the Capability, Requirement and Relationship info
*/
+@Getter
+@Setter
public class CapabilityRequirementRelationship {
private RelationshipInfo relation;
private CapabilityDataDefinition capability;
private RequirementDataDefinition requirement;
+ private List<OperationUi> operations;
- public RelationshipInfo getRelation() {
- return relation;
- }
- public void setRelation(RelationshipInfo relation) {
- this.relation = relation;
- }
- public CapabilityDataDefinition getCapability() {
- return capability;
- }
- public void setCapability(CapabilityDataDefinition capability) {
- this.capability = capability;
- }
- public RequirementDataDefinition getRequirement() {
- return requirement;
- }
- public void setRequirement(RequirementDataDefinition requirement) {
- this.requirement = requirement;
- }
}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
index 5fb07a01b3..7d53abfe21 100644
--- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
@@ -61,6 +61,7 @@ import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.GroupInstanceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ListRequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition;
@@ -71,6 +72,8 @@ import org.openecomp.sdc.be.datatypes.elements.MapInterfaceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapListCapabilityDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapListRequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.RelationshipInstDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
@@ -90,6 +93,7 @@ import org.openecomp.sdc.be.model.operations.StorageException;
import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
+import org.openecomp.sdc.be.ui.model.OperationUi;
import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
import org.openecomp.sdc.common.api.ArtifactTypeEnum;
import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
@@ -1366,12 +1370,13 @@ public class NodeTemplateOperation extends BaseOperation {
return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT));
}
- for (CapabilityRequirementRelationship immutablePair : relationships) {
- String requirement = immutablePair.getRelation().getRequirement();
+ for (final CapabilityRequirementRelationship relationship : relationships) {
+ final String requirement = relationship.getRelation().getRequirement();
- Either<Map<JsonPresentationFields, T>, StorageOperationStatus> associateRes = connectInstancesInContainer(fromNode, toNode, immutablePair.getRelation(), relation.isOriginUI(), calculatedCapabilty, calculatedRequirement,
+ Either<Map<JsonPresentationFields, T>, StorageOperationStatus> associateRes = connectInstancesInContainer(fromNode, toNode, relationship.getRelation(), relation.isOriginUI(), calculatedCapabilty, calculatedRequirement,
fullFilledCapabilty, fullfilledRequirement, compositionDataDefinition, containerV.getUniqueId());
+
if (associateRes.isRight()) {
status = associateRes.right().value();
BeEcompErrorManager.getInstance().logBeFailedAddingResourceInstanceError("AssociateResourceInstances - missing relationship", fromNode, componentId);
@@ -1381,21 +1386,25 @@ public class NodeTemplateOperation extends BaseOperation {
return Either.right(status);
}
- RelationshipInstDataDefinition relationshipInstData = (RelationshipInstDataDefinition) associateRes.left().value().get(JsonPresentationFields.RELATIONSHIP);
+ final Map<JsonPresentationFields, T> relationshipFieldsMap = associateRes.left().value();
+ final RelationshipInstDataDefinition relationshipInstData =
+ (RelationshipInstDataDefinition) relationshipFieldsMap.get(JsonPresentationFields.RELATIONSHIP);
+ createRelationshipInterfaces(relationship.getOperations()).ifPresent(relationshipInstData::setInterfaces);
RelationshipImpl relationshipImplResult = new RelationshipImpl();
relationshipImplResult.setType(relationshipInstData.getType());
RelationshipInfo requirementAndRelationshipPair = new RelationshipInfo(requirement, relationshipImplResult);
- requirementAndRelationshipPair.setCapability(immutablePair.getRelation().getCapability());
- requirementAndRelationshipPair.setRequirement(immutablePair.getRelation().getRequirement());
+ requirementAndRelationshipPair.setCapability(relationship.getRelation().getCapability());
+ requirementAndRelationshipPair.setRequirement(relationship.getRelation().getRequirement());
requirementAndRelationshipPair.setCapabilityOwnerId(relationshipInstData.getCapabilityOwnerId());
requirementAndRelationshipPair.setRequirementOwnerId(relationshipInstData.getRequirementOwnerId());
- requirementAndRelationshipPair.setCapabilityUid(immutablePair.getRelation().getCapabilityUid());
- requirementAndRelationshipPair.setRequirementUid(immutablePair.getRelation().getRequirementUid());
+ requirementAndRelationshipPair.setCapabilityUid(relationship.getRelation().getCapabilityUid());
+ requirementAndRelationshipPair.setRequirementUid(relationship.getRelation().getRequirementUid());
requirementAndRelationshipPair.setId(relationshipInstData.getUniqueId());
CapabilityRequirementRelationship capReqRel = new CapabilityRequirementRelationship();
capReqRel.setRelation(requirementAndRelationshipPair);
- capReqRel.setCapability((CapabilityDataDefinition) associateRes.left().value().get(JsonPresentationFields.CAPABILITY));
- capReqRel.setRequirement((RequirementDataDefinition) associateRes.left().value().get(JsonPresentationFields.REQUIREMENT));
+ capReqRel.setCapability((CapabilityDataDefinition) relationshipFieldsMap.get(JsonPresentationFields.CAPABILITY));
+ capReqRel.setRequirement((RequirementDataDefinition) relationshipFieldsMap.get(JsonPresentationFields.REQUIREMENT));
+ capReqRel.setOperations(relationship.getOperations());
relationshipsResult.add(capReqRel);
CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "update customization UUID for from CI {} and to CI {}", relation.getFromNode(), relation.getToNode());
status = updateCustomizationUUID(relation.getFromNode(), compositionDataDefinition);
@@ -1420,6 +1429,54 @@ public class NodeTemplateOperation extends BaseOperation {
return Either.left(relationsList);
}
+ private 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 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, this::createOperation));
+ interfaceDataDefinition.setOperations(operationMap);
+ }
+ return interfaceDataDefinition;
+ }
+
+ private OperationDataDefinition createOperation(final OperationUi operation) {
+ final OperationDataDefinition operationDataDefinition = new OperationDataDefinition();
+ operationDataDefinition.setName(operation.getOperationType());
+ operationDataDefinition.setUniqueId(UUID.randomUUID().toString());
+ final ArtifactDataDefinition implementation = new ArtifactDataDefinition();
+ implementation.setArtifactName(operation.getImplementation());
+ operationDataDefinition.setImplementation(implementation);
+ 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 StorageOperationStatus updateAllAndCalculatedCapReqOnGraph(String componentId, GraphVertex containerV, Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult,
Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult, Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult,
Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult) {
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 bbda9776f7..8cdced1685 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
@@ -24,6 +24,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -61,6 +62,7 @@ import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.GroupInstanceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ListRequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition;
@@ -70,6 +72,8 @@ import org.openecomp.sdc.be.datatypes.elements.MapInterfaceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapListCapabilityDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapListRequirementDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
import org.openecomp.sdc.be.datatypes.elements.PolicyDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ProductMetadataDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
@@ -119,6 +123,8 @@ import org.openecomp.sdc.be.resources.data.ComponentMetadataData;
import org.openecomp.sdc.be.resources.data.ProductMetadataData;
import org.openecomp.sdc.be.resources.data.ResourceMetadataData;
import org.openecomp.sdc.be.resources.data.ServiceMetadataData;
+import org.openecomp.sdc.be.ui.model.OperationUi;
+import org.openecomp.sdc.be.ui.model.PropertyAssignmentUi;
import org.openecomp.sdc.common.log.wrappers.Logger;
public class ModelConverter {
@@ -444,11 +450,50 @@ public class ModelConverter {
CapabilityRequirementRelationship rel = new CapabilityRequirementRelationship();
RelationshipInfo relationshipPair = getRelationshipInfo(relation);
rel.setRelation(relationshipPair);
+ rel.setOperations(convertToOperations(relation.getInterfaces()));
requirementCapabilityRelDef.setRelationships(Arrays.asList(rel));
return requirementCapabilityRelDef;
}
+ private static List<OperationUi> convertToOperations(final ListDataDefinition<InterfaceDataDefinition> interfaces) {
+ if (interfaces == null || interfaces.isEmpty()) {
+ return Collections.emptyList();
+ }
+ final List<OperationUi> operationUiList = new ArrayList<>();
+ for (final InterfaceDataDefinition interfaceDataDefinition : interfaces.getListToscaDataDefinition()) {
+ if (MapUtils.isEmpty(interfaceDataDefinition.getOperations())) {
+ continue;
+ }
+ for (final Entry<String, OperationDataDefinition> operationEntry :
+ interfaceDataDefinition.getOperations().entrySet()) {
+ final OperationUi operationUi = new OperationUi();
+ operationUi.setOperationType(operationEntry.getKey());
+ operationUi.setInterfaceType(interfaceDataDefinition.getType());
+ final OperationDataDefinition operationDataDefinition = operationEntry.getValue();
+ final ArtifactDataDefinition implementation = operationDataDefinition.getImplementation();
+ if (implementation != null) {
+ operationUi.setImplementation(implementation.getArtifactName());
+ }
+
+ final ListDataDefinition<OperationInputDefinition> inputs = operationDataDefinition.getInputs();
+ if (inputs != null && !inputs.isEmpty()) {
+ final List<OperationInputDefinition> operationInputDefinitionList =
+ inputs.getListToscaDataDefinition();
+ operationInputDefinitionList.forEach(operationInputDefinition -> {
+ final PropertyAssignmentUi propertyAssignmentUi = new PropertyAssignmentUi();
+ propertyAssignmentUi.setName(operationInputDefinition.getLabel());
+ propertyAssignmentUi.setType(operationInputDefinition.getType());
+ propertyAssignmentUi.setValue(operationInputDefinition.getValue());
+ operationUi.addToInputs(propertyAssignmentUi);
+ });
+ }
+ operationUiList.add(operationUi);
+ }
+ }
+ return operationUiList;
+ }
+
/**
* @param relation
* @return
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/OperationUi.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/OperationUi.java
new file mode 100644
index 0000000000..e5c2074c0c
--- /dev/null
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/OperationUi.java
@@ -0,0 +1,43 @@
+/*
+ * ============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.ui.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class OperationUi {
+
+ private String interfaceType;
+ private String operationType;
+ private String implementation;
+ private List<PropertyAssignmentUi> inputs;
+
+ public void addToInputs(final PropertyAssignmentUi input) {
+ if (inputs == null) {
+ inputs = new ArrayList<>();
+ }
+ inputs.add(input);
+ }
+
+}
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/PropertyAssignmentUi.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/PropertyAssignmentUi.java
new file mode 100644
index 0000000000..de6265b3e8
--- /dev/null
+++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/PropertyAssignmentUi.java
@@ -0,0 +1,31 @@
+/*
+ * ============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.ui.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class PropertyAssignmentUi {
+ private String name;
+ private String value;
+ private String type;
+}
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationshipTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationshipTest.java
deleted file mode 100644
index 4a1ee9da6c..0000000000
--- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/CapabilityRequirementRelationshipTest.java
+++ /dev/null
@@ -1,93 +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 org.junit.Test;
-import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
-import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
-
-public class CapabilityRequirementRelationshipTest {
-
- private CapabilityRequirementRelationship createTestSubject() {
- return new CapabilityRequirementRelationship();
- }
-
- @Test
- public void testGetRelation() throws Exception {
- CapabilityRequirementRelationship testSubject;
- RelationshipInfo result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getRelation();
- }
-
- @Test
- public void testSetRelation() throws Exception {
- CapabilityRequirementRelationship testSubject;
- RelationshipInfo relation = null;
-
- // default test
- testSubject = createTestSubject();
- testSubject.setRelation(relation);
- }
-
- @Test
- public void testGetCapability() throws Exception {
- CapabilityRequirementRelationship testSubject;
- CapabilityDataDefinition result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getCapability();
- }
-
- @Test
- public void testSetCapability() throws Exception {
- CapabilityRequirementRelationship testSubject;
- CapabilityDataDefinition capability = null;
-
- // default test
- testSubject = createTestSubject();
- testSubject.setCapability(capability);
- }
-
- @Test
- public void testGetRequirement() throws Exception {
- CapabilityRequirementRelationship testSubject;
- RequirementDataDefinition result;
-
- // default test
- testSubject = createTestSubject();
- result = testSubject.getRequirement();
- }
-
- @Test
- public void testSetRequirement() throws Exception {
- CapabilityRequirementRelationship testSubject;
- RequirementDataDefinition requirement = null;
-
- // default test
- testSubject = createTestSubject();
- testSubject.setRequirement(requirement);
- }
-
-}
diff --git a/catalog-ui/src/app/models/graph/match-relation.ts b/catalog-ui/src/app/models/graph/match-relation.ts
index 2a1b2146b9..3da6775650 100644
--- a/catalog-ui/src/app/models/graph/match-relation.ts
+++ b/catalog-ui/src/app/models/graph/match-relation.ts
@@ -21,7 +21,7 @@
import {Requirement} from "../requirement";
import {Capability} from "../capability";
import {Relationship, RelationshipModel} from "./relationship";
-import {PropertyModel} from "../properties";
+import {Operation} from "../../ng2/pages/composition/graph/connection-wizard/create-interface-operation/model/operation";
export class Match {
requirement:Requirement;
@@ -29,6 +29,7 @@ export class Match {
isFromTo:boolean;
fromNode:string;
toNode:string;
+ operations?:Array<Operation>;
private _relationship:Relationship;
constructor(requirement:Requirement, capability:Capability, isFromTo:boolean, fromNode:string, toNode:string) {
@@ -54,6 +55,7 @@ export class Match {
public matchToRelation = ():Relationship => {
const relationship:Relationship = new Relationship();
relationship.setRelationProperties(this.capability, this.requirement);
+ relationship.operations = this.operations;
return relationship;
};
@@ -74,5 +76,22 @@ export class Match {
relationshipModel.setRelationshipModelParams(this.fromNode, this.toNode, [relationship]);
return relationshipModel;
};
+
+ public addToOperations(operation: Operation): void {
+ if (!this.operations) {
+ this.operations = new Array<Operation>();
+ }
+ this.operations.push(operation);
+ }
+
+ public removeFromOperations(operation: Operation): void {
+ if (!this.operations) {
+ return;
+ }
+ const index = this.operations.indexOf(operation);
+ if (index > -1) {
+ this.operations.splice(index, 1);
+ }
+ }
}
diff --git a/catalog-ui/src/app/models/graph/relationship.ts b/catalog-ui/src/app/models/graph/relationship.ts
index 13a1bd13e0..e39521a66a 100644
--- a/catalog-ui/src/app/models/graph/relationship.ts
+++ b/catalog-ui/src/app/models/graph/relationship.ts
@@ -21,6 +21,7 @@
import * as _ from "lodash";
import {Capability} from "../capability";
import {Requirement} from "../requirement";
+import {Operation} from "../../ng2/pages/composition/graph/connection-wizard/create-interface-operation/model/operation";
export class RelationshipModel {
fromNode:string;
@@ -103,12 +104,19 @@ export class Relationship {
relation: RelationshipType;
capability?: Capability;
requirement?: Requirement;
+ operations?:Array<Operation>;
constructor(fullRelationship?:Relationship) {
if (fullRelationship) {
this.relation = new RelationshipType(fullRelationship.relation);
this.capability = fullRelationship.capability && new Capability(fullRelationship.capability);
this.requirement = fullRelationship.requirement && new Requirement(fullRelationship.requirement);
+ if (fullRelationship.operations) {
+ this.operations = new Array<Operation>();
+ fullRelationship.operations.forEach(operation => {
+ this.operations.push(new Operation(operation));
+ });
+ }
} else {
this.relation = new RelationshipType();
}
@@ -118,7 +126,7 @@ export class Relationship {
this.relation.setRelationProperties(capability, requirement);
this.capability = capability;
this.requirement = requirement;
- };
+ }
public toJSON = ():any => {
let temp = angular.copy(this);
diff --git a/catalog-ui/src/app/models/properties-inputs/property-assignment.ts b/catalog-ui/src/app/models/properties-inputs/property-assignment.ts
new file mode 100644
index 0000000000..0c3ef8370e
--- /dev/null
+++ b/catalog-ui/src/app/models/properties-inputs/property-assignment.ts
@@ -0,0 +1,31 @@
+/*
+ * ============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=========================================================
+ */
+
+export class PropertyAssignment {
+
+ name: string
+ value: string
+ type: string
+
+ constructor(type?: string) {
+ if (type) {
+ this.type = type;
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts
index 45a7d4c576..c48231f2c6 100644
--- a/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/composition-graph.component.ts
@@ -65,6 +65,7 @@ import {
import { CompositionGraphLinkUtils } from './utils/composition-graph-links-utils';
import { CompositionGraphPaletteUtils } from './utils/composition-graph-palette-utils';
import { ServicePathGraphUtils } from './utils/composition-graph-service-path-utils';
+import { RelationshipOperationsStepComponent } from "app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component";
declare const window: any;
@@ -266,6 +267,7 @@ export class CompositionGraphComponent implements AfterViewInit {
steps.push(new StepModel(fromNodeName, FromNodeStepComponent));
steps.push(new StepModel(toNodeName, ToNodeStepComponent));
steps.push(new StepModel('Properties', PropertiesStepComponent));
+ steps.push(new StepModel('Operations', RelationshipOperationsStepComponent));
const wizardTitle = 'Connect: ' + fromNodeName + ' to ' + toNodeName;
const modalInstance = this.modalService.createMultiStepsWizard(wizardTitle, steps, this.createLinkFromMenu, ConnectionWizardHeaderComponent);
modalInstance.instance.open();
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/connection-wizard.module.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/connection-wizard.module.ts
index 80464dc970..5039e573db 100644
--- a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/connection-wizard.module.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/connection-wizard.module.ts
@@ -9,6 +9,19 @@ import {FormElementsModule} from "../../../../components/ui/form-components/form
import {ConnectionWizardHeaderComponent} from "./connection-wizard-header/connection-wizard-header.component";
import {ConnectionPropertiesViewComponent} from "./connection-properties-view/connection-properties-view.component";
import {BrowserModule} from "@angular/platform-browser";
+import {RelationshipOperationsStepComponent} from './relationship-operations-step/relationship-operations-step.component';
+import {InterfaceOperationModule} from "../../../interface-operation/interface-operation.module";
+import {UiElementsModule} from "../../../../components/ui/ui-elements.module";
+import {TranslateModule} from "../../../../shared/translator/translate.module";
+import {SvgIconModule} from "onap-ui-angular/dist/svg-icon/svg-icon.module";
+import {OperationCreatorModule} from "../../../interface-operation/operation-creator/operation-creator.module";
+import {CreateInterfaceOperationComponent} from './create-interface-operation/create-interface-operation.component';
+import {DropdownModule} from "onap-ui-angular/dist/form-elements/dropdown/dropdown.module";
+import {InputModule} from "onap-ui-angular/dist/form-elements/text-elements/input/input.module";
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
+import {SdcUiComponentsModule} from "onap-ui-angular/dist";
+import {CreateInputRowComponent} from './create-interface-operation/create-input-row/create-input-row.component';
+import {InterfaceOperationListComponent} from './relationship-operations-step/interface-operation-list/interface-operation-list.component';
@NgModule({
declarations: [
@@ -16,24 +29,40 @@ import {BrowserModule} from "@angular/platform-browser";
ToNodeStepComponent,
PropertiesStepComponent,
ConnectionWizardHeaderComponent,
- ConnectionPropertiesViewComponent
- ],
- imports: [
- FormElementsModule,
- PropertyTableModule,
- SelectRequirementOrCapabilityModule,
- BrowserModule
+ ConnectionPropertiesViewComponent,
+ RelationshipOperationsStepComponent,
+ CreateInterfaceOperationComponent,
+ CreateInputRowComponent,
+ InterfaceOperationListComponent
],
+ imports: [
+ FormElementsModule,
+ PropertyTableModule,
+ SelectRequirementOrCapabilityModule,
+ BrowserModule,
+ InterfaceOperationModule,
+ UiElementsModule,
+ TranslateModule,
+ SvgIconModule,
+ OperationCreatorModule,
+ DropdownModule,
+ InputModule,
+ FormsModule,
+ SdcUiComponentsModule,
+ ReactiveFormsModule
+ ],
exports: [
FromNodeStepComponent,
ToNodeStepComponent,
PropertiesStepComponent,
+ RelationshipOperationsStepComponent,
ConnectionWizardHeaderComponent,
ConnectionPropertiesViewComponent
],
entryComponents: [FromNodeStepComponent,
ToNodeStepComponent,
PropertiesStepComponent,
+ RelationshipOperationsStepComponent,
ConnectionWizardHeaderComponent,
ConnectionPropertiesViewComponent
],
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.html
new file mode 100644
index 0000000000..5181f32711
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.html
@@ -0,0 +1,53 @@
+<!--
+ ~ ============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=========================================================
+ -->
+
+<div class="cell field-name">
+
+ <div [formGroup]="formGroup">
+ <input id="propertyAssignmentNameInput" class="value-input" formControlName="name"/>
+ </div>
+ <div *ngIf="formName.invalid && (formName.dirty || formName.touched)"
+ class="input-error">
+ <div *ngIf="formName.errors.required">
+ {{'OPERATION_INPUT_NAME_REQUIRED' | translate}}
+ </div>
+ </div>
+</div>
+
+<div class="cell field-type">
+ {{propertyAssignment.type}}
+</div>
+
+<div class="cell field-property">
+ <div [formGroup]="formGroup">
+ <input id="propertyAssignmentValueInput" class="value-input"
+ formControlName="value"/>
+ </div>
+</div>
+
+<div class="cell remove" *ngIf="!isReadOnly">
+ <svg-icon
+ name="trash-o"
+ mode="info"
+ size="small"
+ [attr.data-tests-id]="'propertyAssignment-remove-' + (propertyAssignment.name || 'unnamed')"
+ (click)="onDelete(propertyAssignment)"
+ [clickable]="true">
+ </svg-icon>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.less b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.less
new file mode 100644
index 0000000000..316d49e406
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.less
@@ -0,0 +1,73 @@
+/*
+ * ============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=========================================================
+ */
+
+@import '../../../../../../../../assets/styles/variables.less';
+
+.remove {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ svg-icon {
+ position: relative;
+ right: -3px;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+}
+
+
+.cell {
+ min-height: 50px;
+ padding: 10px;
+ display: flex;
+ align-items: center;
+
+ > * {
+ flex-basis: 100%;
+ }
+
+ /deep/ select {
+ height: 30px;
+ }
+
+ input {
+ height: 30px;
+ padding-left: 10px;
+ text-indent: 6px;
+ border: solid 1px @main_color_o;
+ }
+
+ select {
+ width: 100%;
+ }
+
+ &.field-property {
+ &:last-child {
+ flex: 1;
+ }
+
+ .no-properties-error {
+ color: @func_color_q;
+ font-style: italic;
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.spec.ts
new file mode 100644
index 0000000000..cc1fd52273
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.spec.ts
@@ -0,0 +1,125 @@
+/*
+ * ============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=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {CreateInputRowComponent} from './create-input-row.component';
+import {SdcUiComponentsModule} from "onap-ui-angular/dist";
+import {ReactiveFormsModule} from "@angular/forms";
+import {TranslatePipe} from "../../../../../../shared/translator/translate.pipe";
+import {PropertyAssignment} from "../../../../../../../models/properties-inputs/property-assignment";
+
+describe('CreateInputRowComponent', () => {
+ let component: CreateInputRowComponent;
+ let fixture: ComponentFixture<CreateInputRowComponent>;
+ const nameField = 'name';
+ const valueField = 'value';
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CreateInputRowComponent, TranslatePipe ],
+ imports: [ SdcUiComponentsModule, ReactiveFormsModule ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CreateInputRowComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('form is invalid when empty', () => {
+ expect(component.formGroup.valid).toBeFalsy();
+ });
+
+ it('name field validity', () => {
+ expect(component.formGroup.valid).toBe(false);
+ expect(component.formGroup.contains(nameField)).toBe(true);
+ const nameFormControl = component.formGroup.get(nameField);
+ expect(nameFormControl.valid).toBeFalsy();
+ let validationErrors = nameFormControl.errors || {};
+ expect(validationErrors['required']).toBeTruthy();
+
+ nameFormControl.setValue('');
+ validationErrors = nameFormControl.errors || {};
+ expect(validationErrors['required']).toBeTruthy();
+
+ nameFormControl.setValue('a');
+ expect(nameFormControl.valid).toBeTruthy();
+ });
+
+ it('value field validity', () => {
+ expect(component.formGroup.valid).toBeFalsy();
+ expect(component.formGroup.contains(valueField)).toBeTruthy();
+ const valueFormControl = component.formGroup.get(valueField);
+ expect(valueFormControl.valid).toBeTruthy();
+ });
+
+ it('test set value when form valid', () => {
+ expect(component.formGroup.valid).toBeFalsy();
+ expect(component.propertyAssignment.name).toBeFalsy();
+ expect(component.propertyAssignment.value).toBeFalsy();
+ const nameFormCtrl = component.formGroup.get(nameField);
+ nameFormCtrl.setValue('aName');
+ const valueFormCtrl = component.formGroup.get(valueField);
+ valueFormCtrl.setValue('aValue');
+ expect(component.formGroup.valid).toBeTruthy();
+ expect(component.propertyAssignment.name).toBe('aName');
+ expect(component.propertyAssignment.value).toBe('aValue');
+ });
+
+ it('test propertyAssignment initialization', () => {
+ const propertyAssignment = new PropertyAssignment();
+ propertyAssignment.name = 'aName';
+ propertyAssignment.value = 'aValue';
+ component.propertyAssignment = propertyAssignment;
+ component.ngOnInit();
+ expect(component.formGroup.valid).toBeTruthy();
+ const nameFormCtrl = component.formGroup.get(nameField);
+ expect(nameFormCtrl.value).toBe(propertyAssignment.name);
+ const valueFormCtrl = component.formGroup.get(valueField);
+ expect(valueFormCtrl.value).toBe(propertyAssignment.value);
+ });
+
+ it('test propertyAssignment form binding', () => {
+ const propertyAssignment = new PropertyAssignment();
+ component.propertyAssignment = propertyAssignment;
+ component.ngOnInit();
+ const nameFormCtrl = component.formGroup.get(nameField);
+ nameFormCtrl.setValue('anotherName');
+ const valueFormCtrl = component.formGroup.get(valueField);
+ valueFormCtrl.setValue('anotherValue');
+ expect(nameFormCtrl.value).toBe(propertyAssignment.name);
+ expect(valueFormCtrl.value).toBe(propertyAssignment.value);
+ });
+
+ it('test input deletion', () => {
+ const expectedPropertyAssignment = new PropertyAssignment();
+ let actualPropertyAssignment = null;
+ component.onDeleteEvent.subscribe((value) => actualPropertyAssignment = value);
+ component.onDelete(expectedPropertyAssignment);
+ expect(actualPropertyAssignment).toBe(expectedPropertyAssignment);
+ });
+
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.ts
new file mode 100644
index 0000000000..629c5f3e49
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-input-row/create-input-row.component.ts
@@ -0,0 +1,72 @@
+/*
+ * ============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=========================================================
+ */
+
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {PropertyAssignment} from "../../../../../../../models/properties-inputs/property-assignment";
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {filter} from "rxjs/operators";
+
+@Component({
+ selector: 'app-create-input-row',
+ templateUrl: './create-input-row.component.html',
+ styleUrls: ['./create-input-row.component.less']
+})
+export class CreateInputRowComponent implements OnInit {
+
+ @Input() propertyAssignment: PropertyAssignment;
+ @Input() isReadOnly: boolean;
+ @Output('onDelete') onDeleteEvent: EventEmitter<PropertyAssignment> = new EventEmitter();
+ formGroup: FormGroup;
+
+ constructor() { }
+
+ ngOnInit() {
+ if (!this.propertyAssignment) {
+ this.propertyAssignment = new PropertyAssignment();
+ }
+ this.formGroup = new FormGroup({
+ name: new FormControl(this.propertyAssignment.name, [
+ Validators.required
+ ]),
+ value: new FormControl(this.propertyAssignment.value)
+ });
+
+ this.formGroup.statusChanges
+ .pipe(
+ filter(() => this.formGroup.valid))
+ .subscribe(() => this.onFormValid());
+ }
+
+ onDelete(propertyAssignment: PropertyAssignment) {
+ this.onDeleteEvent.emit(propertyAssignment);
+ }
+
+ get formName() {
+ return this.formGroup.get('name');
+ }
+
+ get formValue() {
+ return this.formGroup.get('value');
+ }
+
+ private onFormValid() {
+ this.propertyAssignment.name = this.formName.value;
+ this.propertyAssignment.value = this.formValue.value;
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.html
new file mode 100644
index 0000000000..a53135c6a9
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.html
@@ -0,0 +1,141 @@
+<!--
+ ~ ============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=========================================================
+ -->
+
+<div class="operation-creator">
+ <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader>
+ <form [formGroup]="form">
+ <div class="w-sdc-form">
+
+ <div class="side-by-side">
+ <div class="form-item">
+ <sdc-dropdown
+ label="{{ 'OPERATION_INTERFACE_TYPE' | translate }}"
+ [required]="true"
+ testId="interface-name"
+ [selectedOption]="selectedInterfaceType"
+ placeHolder="Select..."
+ [disabled]="isReadOnly"
+ (changed)="onSelectInterfaceType($event)"
+ [options]="interfaceTypeOptions">
+ </sdc-dropdown>
+ <div *ngIf="interfaceTypeFormCtrl.invalid && (interfaceTypeFormCtrl.dirty || interfaceTypeFormCtrl.touched)"
+ class="input-error">
+ <div *ngIf="interfaceTypeFormCtrl.errors.required">
+ {{'OPERATION_INTERFACE_REQUIRED_ERROR' | translate}}
+ </div>
+ </div>
+ </div>
+
+ <div class="form-item">
+ <sdc-dropdown
+ #operationDropdown
+ label="{{ 'OPERATION_NAME' | translate }}"
+ [required]="true"
+ testId="operation-name"
+ [selectedOption]="selectedOperation"
+ placeHolder="Select..."
+ [disabled]="isReadOnly"
+ (changed)="onSelectOperation($event)"
+ [options]="operationOptions">
+ </sdc-dropdown>
+ <div *ngIf="operationTypeFormCtrl.invalid && (operationTypeFormCtrl.dirty || operationTypeFormCtrl.touched)"
+ class="input-error">
+ <div *ngIf="operationTypeFormCtrl.errors.required">
+ {{'OPERATION_OPERATION_REQUIRED_ERROR' | translate}}
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="i-sdc-form-item sdc-input">
+ <label for="implementationInput" class="sdc-label__label required">{{ 'OPERATION_IMPLEMENTATION' | translate }}</label>
+ <div class="sdc-input-wrapper">
+ <input id="implementationInput" formControlName="implementation" required="required" class="sdc-input__input"/>
+ </div>
+ <div *ngIf="implementationFormCtrl.invalid && (implementationFormCtrl.dirty || implementationFormCtrl.touched)"
+ class="input-error">
+ <div *ngIf="implementationFormCtrl.errors.required">
+ {{'OPERATION_IMPLEMENTATION_REQUIRED_ERROR' | translate}}
+ </div>
+ <div *ngIf="implementationFormCtrl.errors.minLength">
+ minLength
+ </div>
+ </div>
+ </div>
+
+ <div class="separator-buttons">
+ <tabs tabStyle="round-tabs" [hideIndicationOnTabChange]="true">
+ <tab tabTitle="Inputs"></tab>
+ </tabs>
+ <a
+ class="add-param-link add-btn"
+ *ngIf="!isReadOnly"
+ data-tests-id="addInputParameter"
+ [ngClass]="{'disabled':isReadOnly}"
+ (click)="addInput()">{{ 'OPERATION_ADD_INPUT' | translate }}</a>
+ </div>
+
+ <div class="generic-table">
+ <div class="header-row table-row">
+ <span class="cell header-cell field-name">{{ 'OPERATION_PARAM_NAME' | translate }}</span>
+ <span class="cell header-cell field-type">{{ 'OPERATION_PARAM_TYPE' | translate }}</span>
+ <span class="cell header-cell field-property">
+ {{ 'OPERATION_PARAM_VALUE' | translate }}
+ </span>
+ <span class="cell header-cell remove" *ngIf="!isReadOnly">●●●</span>
+ </div>
+ <div *ngIf="!validateInputs()"
+ class="input-error">
+ <div *ngIf="inputErrorMap.get('duplicatedName')">
+ {{ 'OPERATION_INPUT_NAME_UNIQUE_ERROR' | translate }}
+ </div>
+ <div *ngIf="inputErrorMap.get('invalidName')">
+ {{ 'OPERATION_INPUT_NAME_ERROR' | translate }}
+ </div>
+ </div>
+
+ <app-create-input-row
+ *ngFor="let input of inputs$ | async"
+ class="data-row"
+ [formGroup]=""
+ [propertyAssignment]="input"
+ (onDelete)="onDeleteInput($event)"
+ [isReadOnly]="isReadOnly">
+ </app-create-input-row>
+ </div>
+ <div class="create-interface-operation-footer">
+ <sdc-button class="create-operation-btn"
+ testId="addBtn"
+ [type]="'primary'"
+ [size]="'small'"
+ [text]="'OPERATION_ADD' | translate"
+ [disabled]="form.invalid"
+ (click)="createOperation()">
+ </sdc-button>
+ <sdc-button class="cancel-operation-btn"
+ testId="cancelBtn"
+ [type]="'secondary'"
+ [size]="'small'"
+ [text]="'OPERATION_CANCEL' | translate"
+ (click)="onClickCancel()">
+ </sdc-button>
+ </div>
+ </div>
+ </form>
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less
new file mode 100644
index 0000000000..4c7f8aba48
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.less
@@ -0,0 +1,211 @@
+/*
+ * ============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=========================================================
+ */
+
+@import '../../../../../../../assets/styles/variables.less';
+@import '../../../../../../../assets/styles/override.less';
+
+.operation-creator {
+ font-family: @font-opensans-regular;
+ user-select: none;
+ padding-top: 12px;
+ padding-bottom: 20px;
+
+ .i-sdc-form-label {
+ font-size: 12px;
+ }
+
+ .w-sdc-form .i-sdc-form-item {
+ margin-bottom: 15px;
+ }
+
+ textarea {
+ min-height: 74px;
+ margin-bottom: 18px;
+ }
+
+ /deep/ .sdc-dropdown__component-container {
+ .sdc-dropdown__header {
+ height: 38px;
+ line-height: 35px;
+
+ svg-icon {
+ margin: 13px 6px;
+ }
+ }
+ }
+
+ /deep/ .sdc-input {
+ margin-bottom: 0;
+
+ .sdc-input__input {
+ height: 38px;
+ }
+ }
+
+ .side-by-side {
+ display: flex;
+
+ .form-item {
+ flex: 1;
+
+ &:first-child {
+ margin-right: 14px;
+ flex-basis: 37%;
+ flex-grow: 0;
+ flex-shrink: 0;
+ }
+
+ &:nth-child(3) {
+ margin-left: 14px;
+ flex: 0.4;
+ }
+
+ .i-sdc-form-file-upload {
+ height: 37px;
+ margin-bottom: 0;
+
+ .i-sdc-form-file-name {
+ padding: 8px 10px;
+ }
+
+ .i-sdc-form-file-upload-x-btn {
+ top: 13px;
+ }
+
+ .file-upload-browse-btn {
+ height: 100%;
+ padding: 7px 6px;
+ z-index: 1;
+ }
+ }
+
+ }
+ }
+
+ .archive-warning {
+ font-family: @font-opensans-bold;
+ color: @main_color_i;
+ }
+
+ .no-workflow-warning {
+ font-family: @font-opensans-bold;
+ color: @sdcui_color_red;
+ float: right;
+ }
+
+ .input-param-title {
+ font-size: 16px;
+ text-transform: uppercase;
+ }
+
+ .separator-buttons {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 10px;
+
+ .add-param-link {
+ &:not(.disabled):hover {
+ cursor: pointer;
+ }
+ }
+
+ .tab {
+ width: 84px;
+ text-align: center;
+ }
+ }
+
+ .generic-table {
+ max-height: 244px;
+ min-height: 91px;
+ background: @main_color_p;
+
+ .header-row .header-cell {
+ .info-icon {
+ float: right;
+ position: relative;
+ top: 2px;
+ }
+ /deep/ .tooltip-inner {
+ padding: 2px;
+ max-width: 270px;
+ font-size: 11px;
+ }
+ &.remove {
+ padding: 10px;
+ font-size: 10px;
+ }
+ }
+
+ .data-row {
+ &.empty-msg {
+ .bold-message {
+ font-family: @font-opensans-bold;
+ }
+
+ :first-child {
+ &:not(:only-child) {
+ margin: 6px 0;
+ }
+ }
+
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 14px;
+ }
+ }
+
+ /deep/ .cell {
+ &.field-name, &.field-type {
+ flex: 1;
+ }
+
+ &.field-property {
+ &, &:last-child {
+ flex: 1;
+ }
+ }
+
+ &.field-mandatory {
+ flex: 0.5;
+ text-align: center;
+ }
+
+ &.remove {
+ min-width: 40px;
+ max-width: 40px;
+ }
+ }
+
+ }
+
+ .create-interface-operation-footer {
+ border-top: solid 1px #eaeaea;
+ padding: 10px;
+ margin: 10px;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ sdc-button {
+ margin: 0 5px;
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.spec.ts
new file mode 100644
index 0000000000..8b830e0e62
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.spec.ts
@@ -0,0 +1,234 @@
+/*
+ * ============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=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {CreateInterfaceOperationComponent} from './create-interface-operation.component';
+import {SdcUiComponentsModule} from "onap-ui-angular/dist";
+import {CreateInputRowComponent} from "./create-input-row/create-input-row.component";
+import {FormControl, ReactiveFormsModule} from "@angular/forms";
+import {TabModule} from "../../../../../components/ui/tabs/tabs.module";
+import {UiElementsModule} from "../../../../../components/ui/ui-elements.module";
+import {TranslateService} from "../../../../../shared/translator/translate.service";
+import {TranslatePipe} from "../../../../../shared/translator/translate.pipe";
+import {Operation} from "./model/operation";
+import {PropertyAssignment} from "../../../../../../models/properties-inputs/property-assignment";
+
+describe('CreateInterfaceOperationComponent', () => {
+ let component: CreateInterfaceOperationComponent;
+ let fixture: ComponentFixture<CreateInterfaceOperationComponent>;
+ const interfaceTypeFormName = 'interfaceType';
+ const operationTypeFormName = 'operationType';
+ const implementationFormName = 'implementation';
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [CreateInterfaceOperationComponent, CreateInputRowComponent, TranslatePipe],
+ imports: [SdcUiComponentsModule, ReactiveFormsModule, TabModule,
+ UiElementsModule],
+ providers: [
+ {provide: TranslateService, useValue: {}}
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CreateInterfaceOperationComponent);
+ component = fixture.componentInstance;
+ component.interfaceTypeMap = new Map<string, Array<string>>();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('form is invalid when empty', () => {
+ component.ngOnInit();
+ expect(component.form.valid).toBeFalsy();
+ });
+
+ it('interface type field validity', () => {
+ component.ngOnInit();
+ expect(component.form.valid).toBeFalsy();
+ expect(component.form.contains(interfaceTypeFormName)).toBeTruthy();
+ assertRequiredFormCtrl(component.interfaceTypeFormCtrl, 'anInterfaceType');
+ });
+
+ it('operation type field validity', () => {
+ component.ngOnInit();
+ expect(component.form.valid).toBeFalsy();
+ expect(component.form.contains(operationTypeFormName)).toBeTruthy();
+ assertRequiredFormCtrl(component.operationTypeFormCtrl, 'anOperationType');
+ });
+
+ it('implementation type field validity', () => {
+ component.ngOnInit();
+ expect(component.form.valid).toBeFalsy();
+ expect(component.form.contains(implementationFormName)).toBeTruthy();
+ assertRequiredFormCtrl(component.implementationFormCtrl, 'just/an/implementation.sh');
+ });
+
+ it('test loadInterfaceOptions on init', () => {
+ const interfaceTypeMap = new Map<string, Array<string>>();
+ interfaceTypeMap.set('interface3', new Array<string>());
+ interfaceTypeMap.set('interface4', new Array<string>());
+ interfaceTypeMap.set('interface2', new Array<string>());
+ interfaceTypeMap.set('interface1', new Array<string>());
+ component.interfaceTypeMap = interfaceTypeMap;
+ component.ngOnInit();
+ expect(component.interfaceTypeOptions.length).toBe(4);
+ expect(component.interfaceTypeOptions[0].label).toBe('interface1');
+ expect(component.interfaceTypeOptions[0].value).toBe('interface1');
+ expect(component.interfaceTypeOptions[1].label).toBe('interface2');
+ expect(component.interfaceTypeOptions[1].value).toBe('interface2');
+ expect(component.interfaceTypeOptions[2].label).toBe('interface3');
+ expect(component.interfaceTypeOptions[2].value).toBe('interface3');
+ expect(component.interfaceTypeOptions[3].label).toBe('interface4');
+ expect(component.interfaceTypeOptions[3].value).toBe('interface4');
+ });
+
+ it('test loadOperationOptions on init', () => {
+ const interfaceTypeMap = new Map<string, Array<string>>();
+ const interface1Operations = new Array<string>('interface1Operation3',
+ 'interface1Operation1', 'interface1Operation2', 'interface1Operation4');
+ interfaceTypeMap.set('interface1', interface1Operations);
+ component.interfaceTypeMap = interfaceTypeMap;
+ component.selectedInterfaceType = {
+ value: 'interface1',
+ type: null,
+ label: 'interface1',
+ }
+ component.ngOnInit();
+ expect(component.operationOptions.length).toBe(4);
+ expect(component.operationOptions[0].label).toBe('interface1Operation1');
+ expect(component.operationOptions[0].value).toBe('interface1Operation1');
+ expect(component.operationOptions[1].label).toBe('interface1Operation2');
+ expect(component.operationOptions[1].value).toBe('interface1Operation2');
+ expect(component.operationOptions[2].label).toBe('interface1Operation3');
+ expect(component.operationOptions[2].value).toBe('interface1Operation3');
+ expect(component.operationOptions[3].label).toBe('interface1Operation4');
+ expect(component.operationOptions[3].value).toBe('interface1Operation4');
+ });
+
+ it('test onSelectInterfaceType', () => {
+ const interfaceTypeMap = new Map<string, Array<string>>();
+ interfaceTypeMap.set('interface1', new Array<string>('', '', '', ''));
+ interfaceTypeMap.set('interface2', new Array<string>());
+ component.interfaceTypeMap = interfaceTypeMap;
+ component.ngOnInit();
+ const selectedInterfaceType = {
+ value: 'interface1',
+ type: null,
+ label: 'interface1',
+ }
+ component.onSelectInterfaceType(selectedInterfaceType);
+ expect(component.selectedInterfaceType).toBe(selectedInterfaceType);
+ expect(component.interfaceTypeFormCtrl.value).toBe(selectedInterfaceType.value);
+ expect(component.operationOptions.length).toBe(4);
+ });
+
+ it('test onSelectOperation', () => {
+ component.ngOnInit();
+
+ const selectedOperationType = {
+ value: 'operation1',
+ type: null,
+ label: 'operation1',
+ }
+ component.onSelectOperation(selectedOperationType);
+ expect(component.selectedOperation).toBe(selectedOperationType);
+ expect(component.operationTypeFormCtrl.value).toBe(selectedOperationType.value);
+ });
+
+ it('test onChangeImplementation', () => {
+ component.ngOnInit();
+ let implementation = null;
+ component.onChangeImplementation(implementation);
+ expect(component.implementation).toBe(implementation);
+ implementation = '';
+ component.onChangeImplementation(implementation);
+ expect(component.implementation).toBe(null);
+ implementation = ' ';
+ component.onChangeImplementation(implementation);
+ expect(component.implementation).toBe('');
+ implementation = 'implementation';
+ component.onChangeImplementation(implementation);
+ expect(component.implementation).toBe(implementation);
+ });
+
+ it('test createOperation with valid operation', () => {
+ component.ngOnInit();
+ const interfaceType = 'interfaceType';
+ const operationType = 'operationType';
+ const implementation = 'implementation';
+ component.interfaceTypeFormCtrl.setValue(interfaceType);
+ component.operationTypeFormCtrl.setValue(operationType);
+ component.implementationFormCtrl.setValue(implementation);
+ const inputs = new Array<PropertyAssignment>();
+ const input1 = new PropertyAssignment('string');
+ input1.name = 'input1';
+ input1.value = 'input1Value';
+ inputs.push(input1)
+ component.inputs = inputs;
+ let operation: Operation = null;
+ component.addOperation.subscribe((operation1) => {
+ operation = operation1;
+ });
+ component.createOperation();
+ expect(operation).toBeTruthy();
+ expect(operation.interfaceType).toBe(interfaceType);
+ expect(operation.operationType).toBe(operationType);
+ expect(operation.implementation).toBe(implementation);
+ expect(operation.inputs).toBe(inputs);
+ });
+
+ it('test createOperation with invalid operation', () => {
+ component.ngOnInit();
+ let operation: Operation = null;
+ component.addOperation.subscribe((operation1) => {
+ operation = operation1;
+ });
+ component.createOperation();
+ expect(operation).toBe(null);
+ });
+
+ it('test onDeleteInput with not found input', () => {
+ component.ngOnInit();
+ const input1 = new PropertyAssignment('string');
+ const input2 = new PropertyAssignment('string');
+ input2.name = 'input2';
+ const input3 = new PropertyAssignment('string');
+ input3.name = 'input3';
+ component.inputs = new Array<PropertyAssignment>(input1, input2, input3);
+ component.onDeleteInput(input2);
+ expect(component.inputs.length).toBe(2);
+ expect(component.inputs.find(input => input.name === input2.name)).toBeFalsy();
+ });
+
+ function assertRequiredFormCtrl(formControl: FormControl, valueToSet: any): void {
+ expect(formControl.valid).toBeFalsy();
+ let validationErrors = formControl.errors || {};
+ expect(validationErrors['required']).toBeTruthy();
+ formControl.setValue('');
+ expect(validationErrors['required']).toBeTruthy();
+ formControl.setValue(valueToSet);
+ expect(formControl.valid).toBeTruthy();
+ }
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.ts
new file mode 100644
index 0000000000..9990ac8484
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/create-interface-operation.component.ts
@@ -0,0 +1,235 @@
+/*
+ * ============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=========================================================
+ */
+
+import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
+import {IDropDownOption} from "onap-ui-angular/dist/form-elements/dropdown/dropdown-models";
+import {DropDownComponent} from "onap-ui-angular/dist/components";
+import {PropertyAssignment} from "../../../../../../models/properties-inputs/property-assignment";
+import {Observable} from "rxjs";
+import {Operation} from "./model/operation";
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+
+@Component({
+ selector: 'app-create-interface-operation',
+ templateUrl: './create-interface-operation.component.html',
+ styleUrls: ['./create-interface-operation.component.less']
+})
+export class CreateInterfaceOperationComponent implements OnInit {
+ @Input('interfaceTypeMap') interfaceTypeMap: Map<string, Array<string>>;
+ @Input('operation') private operation: Operation;
+ @Output('addOperation') addOperation: EventEmitter<Operation> = new EventEmitter<Operation>();
+ @ViewChild('operationDropdown') operationDropdown: DropDownComponent;
+
+ form: FormGroup;
+ isLoading: boolean;
+ isReadOnly: boolean;
+ currentInOutTab: string;
+ interfaceTypeOptions: Array<TypedDropDownOption>;
+ operationOptions: Array<TypedDropDownOption>;
+ selectedInterfaceType: TypedDropDownOption;
+ selectedOperation: TypedDropDownOption;
+ implementation: string;
+ inputs$: Observable<Array<PropertyAssignment>>;
+ inputs: Array<PropertyAssignment>;
+ inputErrorMap: Map<string, boolean>;
+ validationMessageList: Array<string>;
+ interfaceTypeFormCtrl: FormControl;
+ operationTypeFormCtrl: FormControl;
+ implementationFormCtrl: FormControl;
+
+ TYPE_INPUT = 'Inputs';
+ TYPE_OUTPUT = 'Outputs';
+
+
+ constructor() {
+ this.currentInOutTab = this.TYPE_INPUT;
+ this.inputErrorMap = new Map<string, boolean>();
+ }
+
+ ngOnInit() {
+ if (!this.operation) {
+ this.operation = new Operation();
+ }
+
+ this.interfaceTypeFormCtrl = new FormControl(this.operation.interfaceType, [
+ Validators.required
+ ]);
+ this.operationTypeFormCtrl = new FormControl(this.operation.operationType, [
+ Validators.required
+ ]);
+ this.implementationFormCtrl = new FormControl(this.operation.implementation, [
+ Validators.required
+ ]);
+ this.form = new FormGroup({
+ interfaceType: this.interfaceTypeFormCtrl,
+ operationType: this.operationTypeFormCtrl,
+ implementation: this.implementationFormCtrl
+ });
+
+ this.isLoading = true;
+ this.isReadOnly = false;
+ this.loadInterfaceOptions();
+ this.loadOperationOptions();
+ this.loadOperationInputs();
+ this.isLoading = false;
+ }
+
+ private loadInterfaceOptions() {
+ this.interfaceTypeOptions = new Array<TypedDropDownOption>();
+ const interfaceTypeList = Array.from(this.interfaceTypeMap.keys());
+ interfaceTypeList.sort();
+ interfaceTypeList.forEach(interfaceType => {
+ this.interfaceTypeOptions.push(this.createInterfaceDropdownOption(interfaceType));
+ });
+ }
+
+ private loadOperationOptions() {
+ this.operationOptions = new Array<TypedDropDownOption>();
+ if (!this.selectedInterfaceType) {
+ return;
+ }
+
+ const operationArray: Array<string> = this.interfaceTypeMap.get(this.selectedInterfaceType.value);
+ operationArray.sort();
+ operationArray.forEach(operationName =>
+ this.operationOptions.push(new TypedDropDownOption(operationName, operationName))
+ );
+ this.operationDropdown.allOptions = <IDropDownOption[]> this.operationOptions;
+ }
+
+ private loadOperationInputs() {
+ this.inputs = new Array<PropertyAssignment>();
+ this.inputs$ = Observable.of(this.inputs);
+ }
+
+ descriptionValue(): string {
+ return this.operation.description;
+ }
+
+ addInput() {
+ this.inputs.push(new PropertyAssignment('string'));
+ }
+
+ onSelectInterfaceType(selectedOption: IDropDownOption) {
+ this.selectedInterfaceType = <TypedDropDownOption> selectedOption;
+ this.operation.interfaceType = selectedOption.value;
+ this.interfaceTypeFormCtrl.setValue(this.operation.interfaceType);
+ this.loadOperationOptions();
+ }
+
+ private createInterfaceDropdownOption(type: string) {
+ let label = type;
+ const lastDot = label.lastIndexOf('.');
+ if (lastDot > -1) {
+ label = label.substr(lastDot + 1);
+ }
+ return new TypedDropDownOption(type, label);
+ }
+
+ onSelectOperation(selectedOption: IDropDownOption) {
+ this.selectedOperation = <TypedDropDownOption> selectedOption;
+ this.operation.operationType = selectedOption.value;
+ this.operationTypeFormCtrl.setValue(this.operation.operationType);
+ }
+
+ onChangeImplementation(implementation: string) {
+ this.implementation = implementation ? implementation.trim() : null;
+ this.operation.implementation = this.implementation;
+ }
+
+ onDeleteInput(input: PropertyAssignment): void {
+ const index = this.inputs.indexOf(input);
+ this.inputs.splice(index, 1);
+ }
+
+ createOperation() {
+ this.form.updateValueAndValidity();
+ if (this.isValid()) {
+ this.operation.interfaceType = this.interfaceTypeFormCtrl.value;
+ this.operation.operationType = this.operationTypeFormCtrl.value;
+ this.operation.implementation = this.implementationFormCtrl.value;
+ if (this.inputs) {
+ this.operation.inputs = this.inputs;
+ }
+ this.addOperation.emit(this.operation);
+ }
+ }
+
+ onClickCancel() {
+ this.addOperation.emit(null);
+ }
+
+ private isValid(): boolean {
+ if (this.form.invalid) {
+ return false;
+ }
+
+ return this.validateInputs();
+ }
+
+ validateInputs(): boolean {
+ this.inputErrorMap = new Map<string, boolean>();
+ if (!this.inputs) {
+ return true;
+ }
+
+ const inputNameSet = new Set<string>();
+ this.inputs.forEach(value => {
+ if (value.name) {
+ value.name = value.name.trim();
+ if (!value.name) {
+ this.inputErrorMap.set('invalidName', true);
+ }
+ } else {
+ this.inputErrorMap.set('invalidName', true);
+ }
+ if (value.value) {
+ value.value = value.value.trim();
+ }
+ //for later check of duplicate input name
+ inputNameSet.add(value.name);
+ });
+
+ if (inputNameSet.size != this.inputs.length) {
+ this.inputErrorMap.set('duplicatedName', true);
+ }
+
+ return this.inputErrorMap.size == 0;
+ }
+
+}
+
+class DropDownOption implements IDropDownOption {
+ value: string;
+ label: string;
+
+ constructor(value: string, label?: string) {
+ this.value = value;
+ this.label = label || value;
+ }
+}
+
+class TypedDropDownOption extends DropDownOption {
+ type: string;
+
+ constructor(value: string, label?: string, type?: string) {
+ super(value, label);
+ this.type = type;
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/model/operation.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/model/operation.ts
new file mode 100644
index 0000000000..d44481dbf9
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/create-interface-operation/model/operation.ts
@@ -0,0 +1,39 @@
+/*
+ * ============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=========================================================
+ */
+
+import {PropertyAssignment} from "../../../../../../../models/properties-inputs/property-assignment";
+
+export class Operation {
+ interfaceType: string;
+ operationType: string;
+ implementation: string;
+ description: string;
+ inputs: Array<PropertyAssignment>;
+
+
+ constructor(operation?:Operation) {
+ if (operation) {
+ this.interfaceType = operation.interfaceType;
+ this.operationType = operation.operationType;
+ this.implementation = operation.implementation;
+ this.description = operation.description;
+ this.inputs = operation.inputs;
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.css b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.css
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.css
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.html
new file mode 100644
index 0000000000..360af52dbf
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.html
@@ -0,0 +1,118 @@
+<!--
+ ~ ============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=========================================================
+ -->
+
+<div class="operation-list">
+
+ <div
+ class="empty-list-container"
+ *ngIf="!(interfaceOperationList$ | async)?.length">
+ <span>No operation provided</span>
+ </div>
+
+ <div *ngIf="(interfaceOperationList$ | async)?.length">
+
+ <div class="expand-collapse">
+ <a
+ class="link"
+ data-tests-id="expand-all"
+ [ngClass]="{'disabled': isAllExpanded()}"
+ (click)="toggleAllExpand()">
+ {{ 'INTERFACE_EXPAND_ALL' | translate }}
+ </a> |
+ <a
+ class="link"
+ data-tests-id="collapse-all"
+ [ngClass]="{'disabled': isAllCollapsed()}"
+ (click)="toggleAllCollapse()">
+ {{ 'INTERFACE_COLLAPSE_ALL' | translate }}
+ </a>
+ </div>
+
+ <div
+ class="interface-row"
+ *ngFor="let interfaceType of getKeys(interfaceTypeMap)">
+
+ <div
+ class="interface-accordion"
+ (click)="toggleCollapse(interfaceType)">
+ <span
+ class="chevron-container"
+ [ngClass]="{'isCollapsed': isInterfaceCollapsed(interfaceType)}">
+ <svg-icon
+ name="caret1-down-o"
+ mode="primary"
+ size="small">
+ </svg-icon>
+ </span>
+ <span class="interface-name">{{interfaceType}}</span>
+ </div>
+
+ <div class="generic-table" *ngIf="isInterfaceCollapsed(interfaceType)">
+ <div class="header-row table-row">
+ <span
+ class="cell header-cell field-name">
+ {{ 'OPERATION_NAME' | translate }}
+ </span>
+ <span
+ class="cell header-cell field-description">
+ {{ 'OPERATION_IMPLEMENTATION' | translate }}
+ </span>
+ <span
+ class="cell header-cell field-actions header-actions">
+ ●●●
+ </span>
+ </div>
+ <div
+ class="data-row"
+ *ngFor="let operation of interfaceTypeMap.get(interfaceType)"
+ [attr.data-tests-id]="'operation-' + operation.operationType"
+ (click)="onEditOperation(operation)">
+ <span
+ class="cell field-name"
+ [attr.data-tests-id]="'operation-' + operation.operationType + '-name'">
+ {{operation.operationType}}
+ </span>
+ <span
+ class="cell field-description"
+ [attr.data-tests-id]="'operation-' + operation.operationType + '-implementation'">
+ {{operation.implementation}}
+ </span>
+ <span class="cell field-actions">
+ <span
+ class="delete-action"
+ [attr.data-tests-id]="'remove-operation-' + operation.operationType"
+ (click)="onRemoveOperation($event, operation)">
+ <svg-icon
+ *ngIf="!isReadOnly"
+ name="trash-o"
+ mode="info"
+ size="small"
+ [clickable]="true">
+ </svg-icon>
+ </span>
+ </span>
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.spec.ts
new file mode 100644
index 0000000000..584edf01d3
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.spec.ts
@@ -0,0 +1,49 @@
+/*
+ * ============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=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {InterfaceOperationListComponent} from './interface-operation-list.component';
+import {UiElementsModule} from "../../../../../../components/ui/ui-elements.module";
+import {SdcUiComponentsModule} from "onap-ui-angular/dist";
+import {TranslatePipe} from "../../../../../../shared/translator/translate.pipe";
+import {TranslateService} from "../../../../../../shared/translator/translate.service";
+
+describe('InterfaceOperationListComponent', () => {
+ let component: InterfaceOperationListComponent;
+ let fixture: ComponentFixture<InterfaceOperationListComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [InterfaceOperationListComponent, TranslatePipe],
+ imports: [SdcUiComponentsModule]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InterfaceOperationListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.ts
new file mode 100644
index 0000000000..e14baf060b
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/interface-operation-list/interface-operation-list.component.ts
@@ -0,0 +1,111 @@
+/*
+ * ============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=========================================================
+ */
+
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {BehaviorSubject} from "rxjs";
+import {Operation} from "../../create-interface-operation/model/operation";
+
+@Component({
+ selector: 'app-interface-operation-list',
+ templateUrl: './interface-operation-list.component.html',
+ styleUrls: ['./interface-operation-list.component.css']
+})
+export class InterfaceOperationListComponent implements OnInit {
+
+ @Input('readonly') isReadOnly: boolean;
+ @Input() set interfaceOperationList(value: Array<Operation>) {
+ this.interfaceOperationList$.next(value);
+ }
+ @Output('onRemoveOperation') onRemoveOperationEmitter: EventEmitter<Operation> = new EventEmitter<Operation>();
+
+ interfaceOperationList$: BehaviorSubject<Array<Operation>>;
+ interfaceTypeMap: Map<string, Array<Operation>>;
+ expandCollapseControlMap: Map<string, boolean>;
+
+ constructor() {
+ this.interfaceOperationList$ = new BehaviorSubject<Array<Operation>>(new Array<Operation>());
+ this.expandCollapseControlMap = new Map<string, boolean>();
+ }
+
+ ngOnInit() {
+ this.loadInterfaces();
+ }
+
+ private loadInterfaces() {
+ this.interfaceOperationList$.subscribe(operationArray => {
+ this.interfaceTypeMap = new Map<string, Array<Operation>>();
+ operationArray.forEach(operation => {
+ if (this.interfaceTypeMap.has(operation.interfaceType)) {
+ let operations = this.interfaceTypeMap.get(operation.interfaceType);
+ operations.push(operation);
+ operations.sort((a, b) => a.operationType.localeCompare(b.operationType));
+ this.interfaceTypeMap.set(operation.interfaceType, operations);
+ } else {
+ this.interfaceTypeMap.set(operation.interfaceType, new Array(operation))
+ }
+ if (!this.expandCollapseControlMap.has(operation.interfaceType)) {
+ this.expandCollapseControlMap.set(operation.interfaceType, true);
+ }
+ });
+ });
+ }
+
+ toggleAllExpand() {
+ this.toggleAll(true);
+ }
+
+ toggleAllCollapse() {
+ this.toggleAll(false);
+ }
+
+ private toggleAll(toggle: boolean) {
+ for (const key of Array.from(this.expandCollapseControlMap.keys())) {
+ this.expandCollapseControlMap.set(key, toggle);
+ }
+ }
+
+ isAllExpanded(): boolean {
+ return Array.from(this.expandCollapseControlMap.values()).every(value => value);
+ }
+
+ isAllCollapsed(): boolean {
+ return Array.from(this.expandCollapseControlMap.values()).every(value => !value);
+ }
+
+
+ onRemoveOperation($event: MouseEvent, operation: any) {
+ this.onRemoveOperationEmitter.emit(operation);
+ }
+
+ onEditOperation(operation?: any) {
+
+ }
+
+ getKeys(interfaceTypeMap: Map<string, Array<Operation>>) {
+ return Array.from(interfaceTypeMap.keys());
+ }
+
+ toggleCollapse(interfaceType: string) {
+ this.expandCollapseControlMap.set(interfaceType, !this.expandCollapseControlMap.get(interfaceType));
+ }
+
+ isInterfaceCollapsed(interfaceType: string): boolean {
+ return this.expandCollapseControlMap.get(interfaceType);
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.html
new file mode 100644
index 0000000000..7c49af88c3
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.html
@@ -0,0 +1,35 @@
+<!--
+ ~ ============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=========================================================
+ -->
+<div class="relationship-operations-container">
+ <div id="relationship-operation-actions" class="actions">
+ <a
+ class="add-param-link add-btn"
+ *ngIf="!enableAddOperation"
+ (click)="addOperation()">{{ 'OPERATION_ADD1' | translate }}</a>
+ </div>
+ <div id="operation-list-container" class="operation-list-container">
+ <app-interface-operation-list [interfaceOperationList]="operationList" [readonly]="false" (onRemoveOperation)="onRemoveOperation($event)"></app-interface-operation-list>
+ </div>
+ <div class="operations-create-container">
+ <div>
+ <app-create-interface-operation *ngIf="enableAddOperation" [interfaceTypeMap]="interfaceTypeMap" (addOperation)="operationAdded($event)">
+ </app-create-interface-operation>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.less b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.less
new file mode 100644
index 0000000000..b2ac1892d9
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.less
@@ -0,0 +1,29 @@
+/*
+ * ============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=========================================================
+ */
+
+.relationship-operations-container {
+ .actions {
+ display: flex;
+ justify-content: flex-end;
+ margin-bottom: 10px;
+ }
+ .operation-list-container {
+ margin: 10px 0 10px 0;
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.spec.ts
new file mode 100644
index 0000000000..9dcf998940
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.spec.ts
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RelationshipOperationsStepComponent } from './relationship-operations-step.component';
+import {CreateInterfaceOperationComponent} from "../create-interface-operation/create-interface-operation.component";
+import {InterfaceOperationListComponent} from "./interface-operation-list/interface-operation-list.component";
+import {TranslatePipe} from "../../../../../shared/translator/translate.pipe";
+import {TranslateService} from "../../../../../shared/translator/translate.service";
+import {SdcUiComponentsModule} from "onap-ui-angular/dist";
+import {CreateInputRowComponent} from "../create-interface-operation/create-input-row/create-input-row.component";
+import {ReactiveFormsModule} from "@angular/forms";
+import {TabModule} from "../../../../../components/ui/tabs/tabs.module";
+import {UiElementsModule} from "../../../../../components/ui/ui-elements.module";
+import {RouterModule} from "@angular/router";
+import {APP_BASE_HREF} from "@angular/common";
+import {ConnectionWizardService} from "../connection-wizard.service";
+import {ComponentServiceNg2} from "../../../../../services/component-services/component.service";
+
+describe('RelationshipOperationsStepComponent', () => {
+ let component: RelationshipOperationsStepComponent;
+ let fixture: ComponentFixture<RelationshipOperationsStepComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ RelationshipOperationsStepComponent, CreateInterfaceOperationComponent,
+ CreateInputRowComponent, InterfaceOperationListComponent, TranslatePipe ],
+ providers: [
+ {provide: TranslateService, useValue: {}},
+ {provide: '$stateParams', useValue: {}},
+ {provide: ConnectionWizardService, useValue: {}},
+ {provide: ComponentServiceNg2, useValue: {}},
+ ],
+ imports: [SdcUiComponentsModule, ReactiveFormsModule, TabModule, UiElementsModule]
+
+
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RelationshipOperationsStepComponent);
+ component = fixture.componentInstance;
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.ts
new file mode 100644
index 0000000000..d595c2b8f6
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/connection-wizard/relationship-operations-step/relationship-operations-step.component.ts
@@ -0,0 +1,163 @@
+/*
+ * ============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=========================================================
+ */
+
+import {Component, Inject, OnInit} from '@angular/core';
+import {IStepComponent} from "../../../../../../models/wizard-step";
+import {ConnectionWizardService} from "../connection-wizard.service";
+import {Component as IComponent} from "../../../../../../models/components/component";
+import {ComponentServiceNg2} from "../../../../../services/component-services/component.service";
+import {Observable} from "rxjs";
+import {Operation} from "../create-interface-operation/model/operation";
+
+@Component({
+ selector: 'app-relationship-operations-step',
+ templateUrl: './relationship-operations-step.component.html',
+ styleUrls: ['./relationship-operations-step.component.less']
+})
+export class RelationshipOperationsStepComponent implements OnInit, IStepComponent {
+
+ private connectionWizardService: ConnectionWizardService;
+ private componentService: ComponentServiceNg2;
+ interfaceTypeMap: Map<string, Array<string>>;
+ component: IComponent;
+ operationList: Array<Operation>;
+ operationList$: Observable<Array<Operation>>;
+ enableAddOperation: boolean;
+
+ constructor(@Inject('$stateParams') private stateParams,
+ connectionWizardService: ConnectionWizardService,
+ componentService: ComponentServiceNg2) {
+ this.component = stateParams.component;
+ this.componentService = componentService;
+ this.connectionWizardService = connectionWizardService;
+ this.interfaceTypeMap = new Map<string, Array<string>>();
+ }
+
+ ngOnInit() {
+ this.loadOperationList();
+ this.loadInterfaceTypeMap();
+ }
+
+ private loadOperationList(): void {
+ if (this.connectionWizardService.selectedMatch.operations) {
+ this.operationList = this.connectionWizardService.selectedMatch.operations.slice();
+ } else {
+ this.operationList = new Array<Operation>();
+ }
+ this.operationList$ = Observable.of(this.operationList);
+ }
+
+ private loadInterfaceTypeMap(): void {
+ this.componentService.getInterfaceTypes(null).subscribe(response => {
+ for (const interfaceType in response) {
+ let operationList = response[interfaceType];
+ //ignore interfaceTypes that doesn't contain operations
+ if (operationList && operationList.length > 0) {
+ //remove operations already on the list
+ const existingOperations =
+ this.operationList.filter(operation => operation.interfaceType === interfaceType);
+ operationList = operationList
+ .filter(operationType => !existingOperations.find(operation => operation.operationType === operationType));
+ if (operationList && operationList.length > 0) {
+ operationList.sort();
+ this.interfaceTypeMap.set(interfaceType, operationList);
+ }
+ }
+ }
+ });
+ }
+
+ preventBack(): boolean {
+ return false;
+ }
+
+ preventNext(): boolean {
+ return false;
+ }
+
+ addOperation() {
+ this.enableAddOperation = !this.enableAddOperation;
+ }
+
+ operationAdded(operation: Operation) {
+ this.enableAddOperation = false;
+ if (operation) {
+ const foundOperation = this.operationList
+ .find(operation1 => operation1.interfaceType === operation.interfaceType
+ && operation1.operationType === operation.operationType);
+ if (foundOperation) {
+ return;
+ }
+ this.operationList.push(operation);
+ this.operationList = this.operationList.slice();
+ this.connectionWizardService.selectedMatch.addToOperations(operation);
+ this.removeFromInterfaceMap(operation);
+ }
+ }
+
+ onRemoveOperation(operation: Operation) {
+ if (!this.operationList) {
+ return;
+ }
+ const index = this.operationList.indexOf(operation);
+ if (index > -1) {
+ this.operationList.splice(index, 1);
+ this.operationList = this.operationList.slice();
+ this.connectionWizardService.selectedMatch.removeFromOperations(operation);
+ this.addToInterfaceMap(operation);
+ }
+ }
+
+ private removeFromInterfaceMap(operation: Operation) {
+ if (!this.interfaceTypeMap.has(operation.interfaceType)) {
+ return;
+ }
+ const operationList = this.interfaceTypeMap.get(operation.interfaceType);
+ if (!operationList) {
+ return;
+ }
+
+ const index = operationList.indexOf(operation.operationType);
+ if (index > -1) {
+ operationList.splice(index, 1);
+ }
+ if (operationList.length == 0) {
+ this.interfaceTypeMap.delete(operation.interfaceType);
+ } else {
+ this.interfaceTypeMap.set(operation.interfaceType, operationList);
+ }
+ }
+
+ private addToInterfaceMap(operation: Operation) {
+ if (!this.interfaceTypeMap.has(operation.interfaceType)) {
+ this.interfaceTypeMap.set(operation.interfaceType, new Array<string>(operation.operationType));
+ return;
+ }
+
+ const operationList = this.interfaceTypeMap.get(operation.interfaceType);
+ if (!operationList) {
+ this.interfaceTypeMap.set(operation.interfaceType, new Array<string>(operation.operationType));
+ return;
+ }
+ operationList.push(operation.operationType);
+ operationList.sort();
+ this.interfaceTypeMap.set(operation.interfaceType, operationList);
+ }
+
+}
diff --git a/catalog-ui/src/assets/languages/en_US.json b/catalog-ui/src/assets/languages/en_US.json
index fd4a3826b3..cc33b36db2 100644
--- a/catalog-ui/src/assets/languages/en_US.json
+++ b/catalog-ui/src/assets/languages/en_US.json
@@ -467,6 +467,7 @@
"OPERATION_INTERFACE_TYPE": "Interface Name",
"OPERATION_NAME": "Operation Name",
+ "OPERATION_IMPLEMENTATION": "Implementation",
"OPERATION_DESCRIPTION": "Description",
"OPERATION_ARTIFACT": "Workflow Artifact",
"OPERATION_WORKFLOW_ASSIGNMENT": "Workflow Assignment",
@@ -475,11 +476,21 @@
"OPERATION_NO_WORKFLOW_CONNECTION": "Failed to Load Workflows",
"OPERATION_WORKFLOW_ARCHIVED": "Archived",
"OPERATION_WORKFLOW_VERSION": "Workflow Version",
- "OPERATION_ADD_PARAMS": "Add Paramaters",
+ "OPERATION_ADD_INPUT": "Add Input",
"OPERATION_PARAM_NAME": "Name",
"OPERATION_PARAM_TYPE": "Type",
+ "OPERATION_PARAM_VALUE": "Value",
"OPERATION_PARAM_PROPERTY": "Property",
"OPERATION_PARAM_MANDATORY": "Mandatory",
+ "OPERATION_ADD": "Add",
+ "OPERATION_ADD1": "Add Operation",
+ "OPERATION_CANCEL": "Cancel",
+ "OPERATION_INTERFACE_REQUIRED_ERROR": "Interface is required",
+ "OPERATION_OPERATION_REQUIRED_ERROR": "Operation is required",
+ "OPERATION_IMPLEMENTATION_REQUIRED_ERROR": "Implementation is required",
+ "OPERATION_INPUT_NAME_UNIQUE_ERROR": "The input names must be unique",
+ "OPERATION_INPUT_NAME_ERROR": "The input name must not be empty or blank",
+ "OPERATION_INPUT_NAME_REQUIRED": "Input name is required",
"EMPTY_PARAM_TABLE_HEADER": "NO PARAMETERS TO SHOW",
"EMPTY_PARAM_TABLE_NO_SELECTED_WORKFLOW_1": "Select Workflow and Workflow Version above",
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/RelationshipInstDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/RelationshipInstDataDefinition.java
index 0c6067af53..8dd00c4370 100644
--- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/RelationshipInstDataDefinition.java
+++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/RelationshipInstDataDefinition.java
@@ -190,6 +190,15 @@ public class RelationshipInstDataDefinition extends ToscaDataDefinition {
setToscaPresentationValue(JsonPresentationFields.MODIFICATION_TIME, modificationTime);
}
+ public void setInterfaces(final ListDataDefinition<InterfaceDataDefinition> operations) {
+ setToscaPresentationValue(JsonPresentationFields.INTERFACES, operations);
+ }
+
+ @SuppressWarnings("unchecked")
+ public ListDataDefinition<InterfaceDataDefinition> getInterfaces() {
+ return (ListDataDefinition<InterfaceDataDefinition>) getToscaPresentationValue(JsonPresentationFields.INTERFACES);
+ }
+
@Override
public String toString() {
String uniqueId = getUniqueId();