Fix 'Wrong Inputs creation on (Add Service)'
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / tosca / ToscaExportHandler.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.tosca;
21
22 import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
23 import static org.apache.commons.collections.MapUtils.isNotEmpty;
24 import static org.openecomp.sdc.be.components.utils.PropertiesUtils.resolvePropertyValueFromInput;
25 import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_ATTRIBUTE;
26 import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_INPUT;
27 import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_PROPERTY;
28
29 import com.fasterxml.jackson.databind.ObjectMapper;
30 import com.google.common.primitives.Ints;
31 import com.google.gson.JsonElement;
32 import com.google.gson.JsonObject;
33 import com.google.gson.JsonParser;
34 import com.google.gson.stream.JsonReader;
35 import fj.data.Either;
36 import java.io.StringReader;
37 import java.nio.file.Path;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.LinkedHashMap;
46 import java.util.LinkedHashSet;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Map.Entry;
50 import java.util.Objects;
51 import java.util.Optional;
52 import java.util.Set;
53 import java.util.function.Supplier;
54 import java.util.stream.Collectors;
55 import org.apache.commons.collections.CollectionUtils;
56 import org.apache.commons.collections.MapUtils;
57 import org.apache.commons.io.FilenameUtils;
58 import org.apache.commons.lang3.StringUtils;
59 import org.apache.commons.lang3.tuple.ImmutablePair;
60 import org.apache.commons.lang3.tuple.ImmutableTriple;
61 import org.apache.commons.lang3.tuple.Triple;
62 import org.onap.sdc.tosca.services.YamlUtil;
63 import org.openecomp.sdc.be.components.impl.exceptions.SdcResourceNotFoundException;
64 import org.openecomp.sdc.be.config.Configuration;
65 import org.openecomp.sdc.be.config.ConfigurationManager;
66 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
67 import org.openecomp.sdc.be.data.model.ToscaImportByModel;
68 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
69 import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition;
70 import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition;
71 import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition;
72 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
73 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
74 import org.openecomp.sdc.be.datatypes.elements.RequirementNodeFilterCapabilityDataDefinition;
75 import org.openecomp.sdc.be.datatypes.elements.RequirementNodeFilterPropertyDataDefinition;
76 import org.openecomp.sdc.be.datatypes.elements.RequirementSubstitutionFilterPropertyDataDefinition;
77 import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterDataDefinition;
78 import org.openecomp.sdc.be.datatypes.elements.ToscaArtifactDataDefinition;
79 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
80 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
81 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
82 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
83 import org.openecomp.sdc.be.exception.ToscaExportException;
84 import org.openecomp.sdc.be.model.ArtifactDefinition;
85 import org.openecomp.sdc.be.model.AttributeDefinition;
86 import org.openecomp.sdc.be.model.CapabilityDefinition;
87 import org.openecomp.sdc.be.model.CapabilityRequirementRelationship;
88 import org.openecomp.sdc.be.model.Component;
89 import org.openecomp.sdc.be.model.ComponentInstance;
90 import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
91 import org.openecomp.sdc.be.model.ComponentInstanceInput;
92 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
93 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
94 import org.openecomp.sdc.be.model.ComponentParametersView;
95 import org.openecomp.sdc.be.model.DataTypeDefinition;
96 import org.openecomp.sdc.be.model.GroupInstance;
97 import org.openecomp.sdc.be.model.InputDefinition;
98 import org.openecomp.sdc.be.model.InterfaceDefinition;
99 import org.openecomp.sdc.be.model.PropertyDefinition;
100 import org.openecomp.sdc.be.model.RelationshipInfo;
101 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
102 import org.openecomp.sdc.be.model.RequirementDefinition;
103 import org.openecomp.sdc.be.model.Resource;
104 import org.openecomp.sdc.be.model.Service;
105 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
106 import org.openecomp.sdc.be.model.category.CategoryDefinition;
107 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
108 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
109 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
110 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
111 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
112 import org.openecomp.sdc.be.model.tosca.converters.ToscaMapValueConverter;
113 import org.openecomp.sdc.be.tosca.PropertyConvertor.PropertyType;
114 import org.openecomp.sdc.be.tosca.builder.ToscaRelationshipBuilder;
115 import org.openecomp.sdc.be.tosca.exception.ToscaConversionException;
116 import org.openecomp.sdc.be.tosca.model.CapabilityFilter;
117 import org.openecomp.sdc.be.tosca.model.NodeFilter;
118 import org.openecomp.sdc.be.tosca.model.SubstitutionMapping;
119 import org.openecomp.sdc.be.tosca.model.ToscaAttribute;
120 import org.openecomp.sdc.be.tosca.model.ToscaCapability;
121 import org.openecomp.sdc.be.tosca.model.ToscaDataType;
122 import org.openecomp.sdc.be.tosca.model.ToscaGroupTemplate;
123 import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
124 import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
125 import org.openecomp.sdc.be.tosca.model.ToscaPolicyTemplate;
126 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
127 import org.openecomp.sdc.be.tosca.model.ToscaPropertyAssignment;
128 import org.openecomp.sdc.be.tosca.model.ToscaRelationshipTemplate;
129 import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
130 import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
131 import org.openecomp.sdc.be.tosca.model.ToscaTemplateArtifact;
132 import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement;
133 import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate;
134 import org.openecomp.sdc.be.tosca.utils.ForwardingPathToscaUtil;
135 import org.openecomp.sdc.be.tosca.utils.InputConverter;
136 import org.openecomp.sdc.be.tosca.utils.OutputConverter;
137 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
138 import org.openecomp.sdc.common.log.wrappers.Logger;
139 import org.openecomp.sdc.tosca.datatypes.ToscaFunctions;
140 import org.springframework.beans.factory.annotation.Autowired;
141 import org.yaml.snakeyaml.DumperOptions;
142 import org.yaml.snakeyaml.DumperOptions.FlowStyle;
143 import org.yaml.snakeyaml.Yaml;
144 import org.yaml.snakeyaml.introspector.BeanAccess;
145 import org.yaml.snakeyaml.introspector.Property;
146 import org.yaml.snakeyaml.introspector.PropertyUtils;
147 import org.yaml.snakeyaml.nodes.MappingNode;
148 import org.yaml.snakeyaml.nodes.Node;
149 import org.yaml.snakeyaml.nodes.NodeTuple;
150 import org.yaml.snakeyaml.nodes.Tag;
151 import org.yaml.snakeyaml.representer.Represent;
152 import org.yaml.snakeyaml.representer.Representer;
153
154 @org.springframework.stereotype.Component("tosca-export-handler")
155 public class ToscaExportHandler {
156
157     public static final String ASSET_TOSCA_TEMPLATE = "assettoscatemplate";
158     private static final Logger log = Logger.getLogger(ToscaExportHandler.class);
159     private static final String INVARIANT_UUID = "invariantUUID";
160     private static final String TOSCA_VERSION = "tosca_simple_yaml_1_3";
161     private static final String SERVICE_NODE_TYPE_PREFIX = "org.openecomp.service.";
162     private static final String IMPORTS_FILE_KEY = "file";
163     private static final String TOSCA_INTERFACE_NAME = "-interface.yml";
164     private static final String FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION = "convertToToscaTemplate - failed to get Default Imports section from configuration";
165     private static final String NOT_SUPPORTED_COMPONENT_TYPE = "Not supported component type {}";
166     private static final String NATIVE_ROOT = "tosca.nodes.Root";
167     private static final List<String> EXCLUDED_CATEGORY_SPECIFIC_METADATA = List
168         .of("Service Function", "Service Role", "Naming Policy", "Service Type");
169     private static final YamlUtil yamlUtil = new YamlUtil();
170     private final ApplicationDataTypeCache applicationDataTypeCache;
171     private final ToscaOperationFacade toscaOperationFacade;
172     private final CapabilityRequirementConverter capabilityRequirementConverter;
173     private final PolicyExportParser policyExportParser;
174     private final GroupExportParser groupExportParser;
175     private final PropertyConvertor propertyConvertor;
176     private final AttributeConverter attributeConverter;
177     private final InputConverter inputConverter;
178     private final OutputConverter outputConverter;
179     private final InterfaceLifecycleOperation interfaceLifecycleOperation;
180     private final InterfacesOperationsConverter interfacesOperationsConverter;
181     private final ModelOperation modelOperation;
182
183     @Autowired
184     public ToscaExportHandler(final ApplicationDataTypeCache applicationDataTypeCache,
185                               final ToscaOperationFacade toscaOperationFacade,
186                               final CapabilityRequirementConverter capabilityRequirementConverter,
187                               final PolicyExportParser policyExportParser,
188                               final GroupExportParser groupExportParser,
189                               final PropertyConvertor propertyConvertor,
190                               final AttributeConverter attributeConverter,
191                               final InputConverter inputConverter,
192                               final OutputConverter outputConverter,
193                               final InterfaceLifecycleOperation interfaceLifecycleOperation,
194                               final InterfacesOperationsConverter interfacesOperationsConverter,
195                               final ModelOperation modelOperation) {
196         this.applicationDataTypeCache = applicationDataTypeCache;
197         this.toscaOperationFacade = toscaOperationFacade;
198         this.capabilityRequirementConverter = capabilityRequirementConverter;
199         this.policyExportParser = policyExportParser;
200         this.groupExportParser = groupExportParser;
201         this.propertyConvertor = propertyConvertor;
202         this.attributeConverter = attributeConverter;
203         this.inputConverter = inputConverter;
204         this.outputConverter = outputConverter;
205         this.interfaceLifecycleOperation = interfaceLifecycleOperation;
206         this.interfacesOperationsConverter = interfacesOperationsConverter;
207         this.modelOperation = modelOperation;
208     }
209
210     public static String getInterfaceFilename(String artifactName) {
211         return artifactName.substring(0, artifactName.lastIndexOf('.')) + TOSCA_INTERFACE_NAME;
212     }
213
214     private static void removeOperationImplementationForProxyNodeType(Map<String, InterfaceDefinition> proxyComponentInterfaces) {
215         if (MapUtils.isEmpty(proxyComponentInterfaces)) {
216             return;
217         }
218         proxyComponentInterfaces.values().stream().map(InterfaceDataDefinition::getOperations).filter(MapUtils::isNotEmpty)
219             .forEach(operations -> operations.values().forEach(operation -> operation.setImplementation(null)));
220     }
221
222     public Either<ToscaRepresentation, ToscaError> exportComponent(Component component) {
223         return convertToToscaTemplate(component).left().map(this::createToscaRepresentation);
224     }
225
226     public Either<ToscaRepresentation, ToscaError> exportComponentInterface(final Component component, final boolean isAssociatedComponent) {
227         final List<Map<String, Map<String, String>>> imports = new ArrayList<>(getDefaultToscaImports(component.getModel()));
228         if (CollectionUtils.isEmpty(imports)) {
229             log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION);
230             return Either.right(ToscaError.GENERAL_ERROR);
231         }
232         List<Triple<String, String, Component>> dependencies = new ArrayList<>();
233         if (component.getDerivedFromGenericType() != null && !component.getDerivedFromGenericType()
234             .startsWith("org.openecomp.resource.abstract.nodes.")) {
235             final Either<Component, StorageOperationStatus> baseType = toscaOperationFacade
236                 .getByToscaResourceNameAndVersion(component.getDerivedFromGenericType(), component.getDerivedFromGenericVersion(),
237                     component.getModel());
238             if (baseType.isLeft() && baseType.left().value() != null) {
239                 addDependencies(imports, dependencies, baseType.left().value());
240             } else {
241                 log.debug("Failed to fetch derived from type {}", component.getDerivedFromGenericType());
242             }
243         }
244
245         String toscaVersion = null;
246         if (component instanceof Resource) {
247             toscaVersion = ((Resource) component).getToscaVersion();
248         }
249         ToscaTemplate toscaTemplate = new ToscaTemplate(toscaVersion != null ? toscaVersion : TOSCA_VERSION);
250         toscaTemplate.setImports(imports);
251         final Map<String, ToscaNodeType> nodeTypes = new HashMap<>();
252         final Either<ToscaTemplate, ToscaError> toscaTemplateRes = convertInterfaceNodeType(new HashMap<>(), component, toscaTemplate, nodeTypes,
253             isAssociatedComponent);
254         if (toscaTemplateRes.isRight()) {
255             return Either.right(toscaTemplateRes.right().value());
256         }
257         toscaTemplate = toscaTemplateRes.left().value();
258         toscaTemplate.setDependencies(dependencies);
259         ToscaRepresentation toscaRepresentation = this.createToscaRepresentation(toscaTemplate);
260         return Either.left(toscaRepresentation);
261     }
262
263     private ToscaRepresentation createToscaRepresentation(ToscaTemplate toscaTemplate) {
264         CustomRepresenter representer = new CustomRepresenter();
265         DumperOptions options = new DumperOptions();
266         options.setAllowReadOnlyProperties(false);
267         options.setPrettyFlow(true);
268         options.setDefaultFlowStyle(FlowStyle.FLOW);
269         options.setCanonical(false);
270         representer.addClassTag(toscaTemplate.getClass(), Tag.MAP);
271         representer.setPropertyUtils(new UnsortedPropertyUtils());
272         Yaml yaml = new Yaml(representer, options);
273         String yamlAsString = yaml.dumpAsMap(toscaTemplate);
274         StringBuilder sb = new StringBuilder();
275         sb.append(getConfiguration().getHeatEnvArtifactHeader());
276         sb.append(yamlAsString);
277         sb.append(getConfiguration().getHeatEnvArtifactFooter());
278         return ToscaRepresentation.make(sb.toString().getBytes(), toscaTemplate);
279     }
280
281     public Either<ToscaTemplate, ToscaError> getDependencies(Component component) {
282         ToscaTemplate toscaTemplate = new ToscaTemplate(null);
283         Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports = fillImports(component, toscaTemplate);
284         if (fillImports.isRight()) {
285             return Either.right(fillImports.right().value());
286         }
287         return Either.left(fillImports.left().value().left);
288     }
289
290     public Either<ToscaTemplate, ToscaError> convertToToscaTemplate(final Component component) {
291         final List<Map<String, Map<String, String>>> defaultToscaImportConfig = getDefaultToscaImports(component.getModel());
292         if (CollectionUtils.isEmpty(defaultToscaImportConfig)) {
293             log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION);
294             return Either.right(ToscaError.GENERAL_ERROR);
295         }
296         log.trace("start tosca export for {}", component.getUniqueId());
297         String toscaVersion = null;
298         if (component instanceof Resource) {
299             toscaVersion = ((Resource) component).getToscaVersion();
300         }
301         final ToscaTemplate toscaTemplate = new ToscaTemplate(toscaVersion != null ? toscaVersion : TOSCA_VERSION);
302         toscaTemplate.setMetadata(convertMetadata(component));
303         toscaTemplate.setImports(new ArrayList<>(defaultToscaImportConfig));
304         final Map<String, ToscaNodeType> nodeTypes = new HashMap<>();
305         if (ModelConverter.isAtomicComponent(component)) {
306             log.trace("convert component as node type");
307             return convertNodeType(new HashMap<>(), component, toscaTemplate, nodeTypes);
308         } else {
309             log.trace("convert component as topology template");
310             return convertToscaTemplate(component, toscaTemplate);
311         }
312     }
313
314     private List<Map<String, Map<String, String>>> getDefaultToscaImports(final String modelId) {
315         if (modelId == null) {
316             return getDefaultToscaImportConfig();
317         }
318
319         final List<ToscaImportByModel> allModelImports = modelOperation.findAllModelImports(modelId, true);
320         final List<Map<String, Map<String, String>>> importList = new ArrayList<>();
321         final Set<Path> addedPathList = new HashSet<>();
322         for (final ToscaImportByModel toscaImportByModel : allModelImports) {
323             var importPath = Path.of(toscaImportByModel.getFullPath());
324             if (addedPathList.contains(importPath)) {
325                 importPath = ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId());
326             }
327             final String fileName = FilenameUtils.getBaseName(importPath.toString());
328             importList.add(Map.of(fileName, Map.of("file", importPath.toString())));
329             addedPathList.add(importPath);
330         }
331         return importList;
332     }
333
334     private Either<ToscaTemplate, ToscaError> convertToscaTemplate(Component component, ToscaTemplate toscaNode) {
335         Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> importsRes = fillImports(component, toscaNode);
336         if (importsRes.isRight()) {
337             return Either.right(importsRes.right().value());
338         }
339         toscaNode = importsRes.left().value().left;
340         Map<String, Component> componentCache = importsRes.left().value().right;
341         Either<Map<String, ToscaNodeType>, ToscaError> nodeTypesMapEither = createProxyNodeTypes(componentCache, component);
342         if (nodeTypesMapEither.isRight()) {
343             log.debug("Failed to fetch normative service proxy resource by tosca name, error {}", nodeTypesMapEither.right().value());
344             return Either.right(nodeTypesMapEither.right().value());
345         }
346         Map<String, ToscaNodeType> nodeTypesMap = nodeTypesMapEither.left().value();
347         if (nodeTypesMap != null && !nodeTypesMap.isEmpty()) {
348             toscaNode.setNode_types(nodeTypesMap);
349         }
350         createServiceSubstitutionNodeTypes(componentCache, component, toscaNode);
351         Either<Map<String, Object>, ToscaError> proxyInterfaceTypesEither = createProxyInterfaceTypes(component);
352         if (proxyInterfaceTypesEither.isRight()) {
353             log.debug("Failed to populate service proxy local interface types in tosca, error {}", nodeTypesMapEither.right().value());
354             return Either.right(proxyInterfaceTypesEither.right().value());
355         }
356         Map<String, Object> proxyInterfaceTypes = proxyInterfaceTypesEither.left().value();
357         if (MapUtils.isNotEmpty(proxyInterfaceTypes)) {
358             toscaNode.setInterface_types(proxyInterfaceTypes);
359         }
360         Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> dataTypesEither = applicationDataTypeCache.getAll(component.getModel());
361         if (dataTypesEither.isRight()) {
362             log.debug("Failed to retrieve all data types {}", dataTypesEither.right().value());
363             return Either.right(ToscaError.GENERAL_ERROR);
364         }
365         Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value();
366         ToscaTopolgyTemplate topologyTemplate = new ToscaTopolgyTemplate();
367         List<InputDefinition> inputDef = component.getInputs();
368         Map<String, ToscaProperty> inputs = inputConverter.convertInputs(inputDef, dataTypes);
369         if (!inputs.isEmpty()) {
370             topologyTemplate.setInputs(inputs);
371         }
372         final Map<String, ToscaProperty> outputs;
373         try {
374             outputs = outputConverter.convert(component.getOutputs(), dataTypes);
375         } catch (final ToscaConversionException e) {
376             log.error(EcompLoggerErrorCode.SCHEMA_ERROR, ToscaExportHandler.class.getName(),
377                 "Could not parse component '{}' outputs. Component unique id '{}'.", component.getName(), component.getUniqueId(), e);
378             return Either.right(ToscaError.GENERAL_ERROR);
379         }
380         if (!outputs.isEmpty()) {
381             topologyTemplate.setOutputs(outputs);
382         }
383         if (CollectionUtils.isNotEmpty(component.getComponentInstances())) {
384             final Either<Map<String, ToscaNodeTemplate>, ToscaError> nodeTemplates =
385                 convertNodeTemplates(component, componentCache, dataTypes, topologyTemplate);
386             if (nodeTemplates.isRight()) {
387                 return Either.right(nodeTemplates.right().value());
388             }
389             log.debug("node templates converted");
390             topologyTemplate.setNode_templates(nodeTemplates.left().value());
391         }
392         final Map<String, ToscaRelationshipTemplate> relationshipTemplatesMap = new ToscaExportRelationshipTemplatesHandler()
393             .createFrom(topologyTemplate.getNode_templates());
394         if (!relationshipTemplatesMap.isEmpty()) {
395             topologyTemplate.setRelationshipTemplates(relationshipTemplatesMap);
396         }
397         addGroupsToTopologyTemplate(component, topologyTemplate);
398         try {
399             addPoliciesToTopologyTemplate(component, topologyTemplate);
400         } catch (SdcResourceNotFoundException e) {
401             log.debug("Fail to add policies to topology template:", e);
402             return Either.right(ToscaError.GENERAL_ERROR);
403         }
404         try {
405             createSubstitutionMapping(component, componentCache).ifPresent(topologyTemplate::setSubstitution_mappings);
406         } catch (final ToscaExportException e) {
407             log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, ToscaExportHandler.class.getName(), e.getMessage());
408             return Either.right(e.getToscaError());
409         }
410         if (!topologyTemplate.isEmpty()) {
411             toscaNode.setTopology_template(topologyTemplate);
412         }
413         return Either.left(toscaNode);
414     }
415
416     private Either<String, ToscaError> createComponentToscaName(final Component component) {
417         switch (component.getComponentType()) {
418             case RESOURCE:
419                 final ResourceMetadataDataDefinition resourceMetadata =
420                     (ResourceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition();
421                 return Either.left(resourceMetadata.getToscaResourceName());
422             case SERVICE:
423                 return Either.left(SERVICE_NODE_TYPE_PREFIX + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName());
424             default:
425                 log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType());
426                 return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE);
427         }
428     }
429
430     private Optional<SubstitutionMapping> createSubstitutionMapping(final Component component,
431                                                                     final Map<String, Component> componentCache) throws ToscaExportException {
432         if (component instanceof Service && !((Service) component).isSubstituteCandidate()) {
433             return Optional.empty();
434         }
435
436         final Either<String, ToscaError> toscaResourceNameEither = createComponentToscaName(component);
437         if (toscaResourceNameEither.isRight()) {
438             throw new ToscaExportException("Could not create component TOSCA name", toscaResourceNameEither.right().value());
439         }
440         final String toscaResourceName = toscaResourceNameEither.left().value();
441
442         final SubstitutionMapping substitutionMapping = new SubstitutionMapping();
443         substitutionMapping.setNode_type(toscaResourceName);
444         convertSubstitutionMappingFilter(component).ifPresent(substitutionMapping::setSubstitution_filter);
445
446         final Either<Map<String, String[]>, ToscaError> capabilitiesEither = convertSubstitutionMappingCapabilities(component, componentCache);
447         if (capabilitiesEither.isRight()) {
448             throw new ToscaExportException("Could not convert substitution mapping capabilities", capabilitiesEither.right().value());
449         }
450         final Map<String, String[]> capabilityMap = capabilitiesEither.left().value();
451         if (!capabilityMap.isEmpty()) {
452             substitutionMapping.setCapabilities(capabilityMap);
453         }
454
455         final Either<Map<String, String[]>, ToscaError> requirements =
456             capabilityRequirementConverter.convertSubstitutionMappingRequirements(component, componentCache);
457         if (requirements.isRight()) {
458             throw new ToscaExportException("Could not convert substitution mapping requirements", requirements.right().value());
459         }
460         final Map<String, String[]> requirementMap = requirements.left().value();
461         if (MapUtils.isNotEmpty(requirementMap)) {
462             substitutionMapping.setRequirements(requirementMap);
463         }
464
465         final Map<String, String[]> propertyMappingMap = buildSubstitutionMappingPropertyMapping(component);
466         if (MapUtils.isNotEmpty(propertyMappingMap)) {
467             substitutionMapping.setProperties(propertyMappingMap);
468         }
469
470         final Map<String, String[]> attributesMappingMap = buildSubstitutionMappingAttributesMapping(component);
471         if (MapUtils.isNotEmpty(attributesMappingMap)) {
472             substitutionMapping.setAttributes(attributesMappingMap);
473         }
474
475         return Optional.of(substitutionMapping);
476     }
477
478     private Optional<NodeFilter> convertSubstitutionMappingFilter(final Component component) {
479         if (component.getSubstitutionFilter() == null || (component.getSubstitutionFilter().getProperties()).getListToscaDataDefinition() == null) {
480             return Optional.empty();
481         }
482
483         return Optional.ofNullable(convertToSubstitutionFilterComponent(component.getSubstitutionFilter()));
484     }
485
486     private void addGroupsToTopologyTemplate(Component component, ToscaTopolgyTemplate topologyTemplate) {
487         Map<String, ToscaGroupTemplate> groups = groupExportParser.getGroups(component);
488         if (groups != null) {
489             topologyTemplate.addGroups(groups);
490         }
491     }
492
493     private void addPoliciesToTopologyTemplate(Component component, ToscaTopolgyTemplate topologyTemplate) throws SdcResourceNotFoundException {
494         Map<String, ToscaPolicyTemplate> policies = policyExportParser.getPolicies(component);
495         if (policies != null) {
496             topologyTemplate.addPolicies(policies);
497         }
498     }
499
500     private Map<String, String> convertMetadata(Component component) {
501         return convertMetadata(component, false, null);
502     }
503
504     private Map<String, String> convertMetadata(Component component, boolean isInstance, ComponentInstance componentInstance) {
505         Map<String, String> toscaMetadata = new LinkedHashMap<>();
506         toscaMetadata.put(convertMetadataKey(JsonPresentationFields.INVARIANT_UUID), component.getInvariantUUID());
507         toscaMetadata.put(JsonPresentationFields.UUID.getPresentation(), component.getUUID());
508         toscaMetadata
509             .put(JsonPresentationFields.NAME.getPresentation(), component.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
510         toscaMetadata.put(JsonPresentationFields.DESCRIPTION.getPresentation(), component.getDescription());
511         List<CategoryDefinition> categories = component.getCategories();
512         CategoryDefinition categoryDefinition = categories.get(0);
513         toscaMetadata.put(JsonPresentationFields.MODEL.getPresentation(), component.getModel());
514         toscaMetadata.put(JsonPresentationFields.CATEGORY.getPresentation(), categoryDefinition.getName());
515         if (isInstance) {
516             toscaMetadata.put(JsonPresentationFields.VERSION.getPresentation(), component.getVersion());
517             toscaMetadata.put(JsonPresentationFields.CUSTOMIZATION_UUID.getPresentation(), componentInstance.getCustomizationUUID());
518             if (componentInstance.getSourceModelInvariant() != null && !componentInstance.getSourceModelInvariant().isEmpty()) {
519                 toscaMetadata.put(JsonPresentationFields.VERSION.getPresentation(), componentInstance.getComponentVersion());
520                 toscaMetadata.put(JsonPresentationFields.CI_SOURCE_MODEL_INVARIANT.getPresentation(), componentInstance.getSourceModelInvariant());
521                 toscaMetadata.put(JsonPresentationFields.CI_SOURCE_MODEL_UUID.getPresentation(), componentInstance.getSourceModelUuid());
522                 toscaMetadata.put(JsonPresentationFields.CI_SOURCE_MODEL_NAME.getPresentation(), componentInstance.getSourceModelName());
523                 if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) {
524                     toscaMetadata.put(JsonPresentationFields.NAME.getPresentation(),
525                         componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceProxy.getDisplayValue());
526                 } else if (componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) {
527                     toscaMetadata.put(JsonPresentationFields.NAME.getPresentation(),
528                         componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceSubstitution.getDisplayValue());
529                 }
530                 toscaMetadata.put(JsonPresentationFields.DESCRIPTION.getPresentation(), componentInstance.getDescription());
531             }
532         }
533         switch (component.getComponentType()) {
534             case RESOURCE:
535                 Resource resource = (Resource) component;
536                 if (isInstance && (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy
537                     || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution)) {
538                     toscaMetadata.put(JsonPresentationFields.TYPE.getPresentation(), componentInstance.getOriginType().getDisplayValue());
539                 } else {
540                     toscaMetadata.put(JsonPresentationFields.TYPE.getPresentation(), resource.getResourceType().name());
541                 }
542                 toscaMetadata.put(JsonPresentationFields.SUB_CATEGORY.getPresentation(), categoryDefinition.getSubcategories().get(0).getName());
543                 toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR.getPresentation(), resource.getVendorName());
544                 toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_RELEASE.getPresentation(), resource.getVendorRelease());
545                 toscaMetadata.put(JsonPresentationFields.RESOURCE_VENDOR_MODEL_NUMBER.getPresentation(), resource.getResourceVendorModelNumber());
546                 break;
547             case SERVICE:
548                 Service service = (Service) component;
549                 toscaMetadata.put(JsonPresentationFields.TYPE.getPresentation(), component.getComponentType().getValue());
550                 toscaMetadata.put(JsonPresentationFields.SERVICE_TYPE.getPresentation(), service.getServiceType());
551                 toscaMetadata.put(JsonPresentationFields.SERVICE_ROLE.getPresentation(), service.getServiceRole());
552                 toscaMetadata.put(JsonPresentationFields.SERVICE_FUNCTION.getPresentation(), service.getServiceFunction());
553                 toscaMetadata.put(JsonPresentationFields.ENVIRONMENT_CONTEXT.getPresentation(), service.getEnvironmentContext());
554                 toscaMetadata.put(JsonPresentationFields.INSTANTIATION_TYPE.getPresentation(),
555                     service.getEnvironmentContext() == null ? StringUtils.EMPTY : service.getInstantiationType());
556                 if (!isInstance) {
557                     // DE268546
558                     toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(), service.isEcompGeneratedNaming().toString());
559                     toscaMetadata.put(JsonPresentationFields.ECOMP_GENERATED_NAMING.getPresentation(), service.isEcompGeneratedNaming().toString());
560                     toscaMetadata.put(JsonPresentationFields.NAMING_POLICY.getPresentation(), service.getNamingPolicy());
561                 }
562                 break;
563             default:
564                 log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType());
565         }
566         for (final String key : component.getCategorySpecificMetadata().keySet()) {
567             if (!EXCLUDED_CATEGORY_SPECIFIC_METADATA.contains(key)) {
568                 toscaMetadata.put(key, component.getCategorySpecificMetadata().get(key));
569             }
570         }
571         return toscaMetadata;
572     }
573
574     private String convertMetadataKey(JsonPresentationFields jsonPresentationField) {
575         if (JsonPresentationFields.INVARIANT_UUID.equals(jsonPresentationField)) {
576             return INVARIANT_UUID;
577         }
578         return jsonPresentationField.getPresentation();
579     }
580
581     private Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports(Component component, ToscaTemplate toscaTemplate) {
582         final List<Map<String, Map<String, String>>> defaultToscaImportConfig = getDefaultToscaImports(component.getModel());
583         if (CollectionUtils.isEmpty(defaultToscaImportConfig)) {
584             log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION);
585             return Either.right(ToscaError.GENERAL_ERROR);
586         }
587         Map<String, Component> componentCache = new HashMap<>();
588         if (!ModelConverter.isAtomicComponent(component)) {
589             final List<Map<String, Map<String, String>>> additionalImports =
590                 toscaTemplate.getImports() == null ? new ArrayList<>(defaultToscaImportConfig) : new ArrayList<>(toscaTemplate.getImports());
591             List<Triple<String, String, Component>> dependencies = new ArrayList<>();
592             Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts();
593             final Map<String, Map<String, String>> substituteTypeImportEntry = generateComponentSubstituteTypeImport(component, toscaArtifacts);
594             if (!substituteTypeImportEntry.isEmpty()) {
595                 additionalImports.add(substituteTypeImportEntry);
596             }
597             List<ComponentInstance> componentInstances = component.getComponentInstances();
598             if (componentInstances != null && !componentInstances.isEmpty()) {
599                 componentInstances.forEach(ci -> createDependency(componentCache, additionalImports, dependencies, ci));
600             }
601             toscaTemplate.setDependencies(dependencies);
602             toscaTemplate.setImports(additionalImports);
603         } else {
604             log.debug("currently imports supported for VF and service only");
605         }
606         return Either.left(new ImmutablePair<>(toscaTemplate, componentCache));
607     }
608
609     private Map<String, Map<String, String>> generateComponentSubstituteTypeImport(final Component component,
610                                                                                    final Map<String, ArtifactDefinition> toscaArtifacts) {
611
612         if (component instanceof Service && !((Service) component).isSubstituteCandidate()) {
613             return Collections.emptyMap();
614         }
615         if (MapUtils.isEmpty(toscaArtifacts)) {
616             return Collections.emptyMap();
617         }
618         final ArtifactDefinition artifactDefinition = toscaArtifacts.get(ASSET_TOSCA_TEMPLATE);
619         if (artifactDefinition == null) {
620             return Collections.emptyMap();
621         }
622         final var importEntryName = component.getComponentType().toString().toLowerCase() + "-" + component.getName() + "-interface";
623         return Map.of(importEntryName,
624             Map.of(IMPORTS_FILE_KEY, getInterfaceFilename(artifactDefinition.getArtifactName()))
625         );
626     }
627
628     private List<Map<String, Map<String, String>>> getDefaultToscaImportConfig() {
629         return getConfiguration().getDefaultImports();
630     }
631
632     private void createDependency(final Map<String, Component> componentCache, final List<Map<String, Map<String, String>>> imports,
633                                   final List<Triple<String, String, Component>> dependencies, final ComponentInstance componentInstance) {
634         log.debug("createDependency componentCache {}", componentCache);
635         Component componentRI = componentCache.get(componentInstance.getComponentUid());
636         if (componentRI == null || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) {
637             // all resource must be only once!
638             final Either<Component, StorageOperationStatus> resource = toscaOperationFacade.getToscaFullElement(componentInstance.getComponentUid());
639             if ((resource.isRight()) && (log.isDebugEnabled())) {
640                 log.debug("Failed to fetch resource with id {} for instance {}", componentInstance.getComponentUid(),
641                     componentInstance.getUniqueId());
642                 return;
643             }
644             final Component fetchedComponent = resource.left().value();
645             componentRI = setComponentCache(componentCache, componentInstance, fetchedComponent);
646             addDependencies(imports, dependencies, componentRI);
647         }
648     }
649
650     /**
651      * Sets a componentCache from the given component/resource.
652      */
653     private Component setComponentCache(final Map<String, Component> componentCache, final ComponentInstance componentInstance,
654                                         final Component fetchedComponent) {
655         componentCache.put(fetchedComponent.getUniqueId(), fetchedComponent);
656         if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy
657             || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) {
658             final Either<Component, StorageOperationStatus> sourceService = toscaOperationFacade
659                 .getToscaFullElement(componentInstance.getSourceModelUid());
660             if (sourceService.isRight() && (log.isDebugEnabled())) {
661                 log.debug("Failed to fetch source service with id {} for proxy {}", componentInstance.getSourceModelUid(),
662                     componentInstance.getUniqueId());
663             }
664             final Component fetchedSource = sourceService.left().value();
665             componentCache.put(fetchedSource.getUniqueId(), fetchedSource);
666             return fetchedSource;
667         }
668         return fetchedComponent;
669     }
670
671     /**
672      * Retrieves all derived_from nodes and stores it in a predictable order.
673      */
674     private void addDependencies(final List<Map<String, Map<String, String>>> imports, final List<Triple<String, String, Component>> dependencies,
675                                  final Component fetchedComponent) {
676         final Set<Component> componentsList = new LinkedHashSet<>();
677         if (fetchedComponent instanceof Resource) {
678             log.debug("fetchedComponent is a resource {}", fetchedComponent);
679             final Optional<Map<String, String>> derivedFromMapOfIdToName = getDerivedFromMapOfIdToName(fetchedComponent, componentsList);
680             if (derivedFromMapOfIdToName.isPresent() && !derivedFromMapOfIdToName.get().isEmpty()) {
681                 derivedFromMapOfIdToName.get().entrySet().forEach(entry -> {
682                     log.debug("Started entry.getValue() : {}", entry.getValue());
683                     if (!NATIVE_ROOT.equals(entry.getValue())) {
684                         Either<Resource, StorageOperationStatus> resourcefetched = toscaOperationFacade.getToscaElement(entry.getKey());
685                         if (resourcefetched != null && resourcefetched.isLeft()) {
686                             componentsList.add(resourcefetched.left().value());
687                         }
688                     }
689                 });
690                 setImports(imports, dependencies, componentsList);
691             } else {
692                 setImports(imports, dependencies, fetchedComponent);
693             }
694         }
695     }
696
697     /**
698      * Returns all derived_from nodes found.
699      */
700     private Optional<Map<String, String>> getDerivedFromMapOfIdToName(final Component fetchedComponent, final Set<Component> componentsList) {
701         final Resource parentResource = (Resource) fetchedComponent;
702         Map<String, String> derivedFromMapOfIdToName = new HashMap<>();
703         if (CollectionUtils.isNotEmpty(parentResource.getComponentInstances())) {
704             componentsList.add(fetchedComponent);
705             for (final ComponentInstance componentInstance : parentResource.getComponentInstances()) {
706                 final Either<Resource, StorageOperationStatus> resourcefetched = toscaOperationFacade
707                     .getToscaElement(componentInstance.getComponentUid());
708                 if (resourcefetched != null && resourcefetched.isLeft()) {
709                     final Map<String, String> derivedWithId = resourcefetched.left().value().getDerivedFromMapOfIdToName();
710                     if (MapUtils.isNotEmpty(derivedWithId)) {
711                         derivedFromMapOfIdToName.putAll(derivedWithId);
712                     }
713                 }
714             }
715         } else {
716             derivedFromMapOfIdToName = parentResource.getDerivedFromMapOfIdToName();
717         }
718         log.debug("Started derivedFromMapOfIdToName: {}", derivedFromMapOfIdToName);
719         return Optional.ofNullable(derivedFromMapOfIdToName);
720     }
721
722     /**
723      * Creates a resource map and adds it to the import list.
724      */
725     private void setImports(final List<Map<String, Map<String, String>>> imports, final List<Triple<String, String, Component>> dependencies,
726                             final Set<Component> componentsList) {
727         componentsList.forEach(component -> setImports(imports, dependencies, component));
728     }
729
730     private void setImports(final List<Map<String, Map<String, String>>> imports, final List<Triple<String, String, Component>> dependencies,
731                             final Component component) {
732         final Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts();
733         final ArtifactDefinition artifactDefinition = toscaArtifacts.get(ASSET_TOSCA_TEMPLATE);
734         if (artifactDefinition != null) {
735             final Map<String, String> files = new HashMap<>();
736             final String artifactName = artifactDefinition.getArtifactName();
737             files.put(IMPORTS_FILE_KEY, artifactName);
738             final StringBuilder keyNameBuilder = new StringBuilder();
739             keyNameBuilder.append(component.getComponentType().toString().toLowerCase());
740             keyNameBuilder.append("-");
741             keyNameBuilder.append(component.getName());
742             addImports(imports, keyNameBuilder, files);
743             dependencies.add(new ImmutableTriple<>(artifactName, artifactDefinition.getEsId(), component));
744             if (!ModelConverter.isAtomicComponent(component)) {
745                 final Map<String, String> interfaceFiles = new HashMap<>();
746                 interfaceFiles.put(IMPORTS_FILE_KEY, getInterfaceFilename(artifactName));
747                 keyNameBuilder.append("-interface");
748                 addImports(imports, keyNameBuilder, interfaceFiles);
749             }
750         }
751     }
752
753     /**
754      * Adds the found resource to the import definition list.
755      */
756     private void addImports(final List<Map<String, Map<String, String>>> imports, final StringBuilder keyNameBuilder,
757                             final Map<String, String> files) {
758         final String mapKey = keyNameBuilder.toString();
759         if (imports.stream().allMatch(stringMapMap -> stringMapMap.get(mapKey) == null)) {
760             final Map<String, Map<String, String>> importsListMember = new HashMap<>();
761             importsListMember.put(keyNameBuilder.toString(), files);
762             imports.add(importsListMember);
763         }
764     }
765
766     private Either<ToscaTemplate, ToscaError> convertNodeType(Map<String, Component> componentsCache, Component component, ToscaTemplate toscaNode,
767                                                               Map<String, ToscaNodeType> nodeTypes) {
768         return convertInterfaceNodeType(componentsCache, component, toscaNode, nodeTypes, false);
769     }
770
771     public Either<ToscaTemplate, ToscaError> convertInterfaceNodeType(Map<String, Component> componentsCache, Component component,
772                                                                       ToscaTemplate toscaNode, Map<String, ToscaNodeType> nodeTypes,
773                                                                       boolean isAssociatedComponent) {
774         log.debug("start convert node type for {}", component.getUniqueId());
775         ToscaNodeType toscaNodeType = createNodeType(component);
776         Either<Map<String, InterfaceDefinition>, StorageOperationStatus> lifecycleTypeEither = interfaceLifecycleOperation
777             .getAllInterfaceLifecycleTypes(component.getModel());
778         if (lifecycleTypeEither.isRight() && !StorageOperationStatus.NOT_FOUND.equals(lifecycleTypeEither.right().value())) {
779             log.debug("Failed to fetch all interface types :", lifecycleTypeEither.right().value());
780             return Either.right(ToscaError.GENERAL_ERROR);
781         }
782         if (lifecycleTypeEither.isLeft()) {
783             List<String> allGlobalInterfaceTypes = lifecycleTypeEither.left().value().values().stream().map(InterfaceDataDefinition::getType)
784                 .collect(Collectors.toList());
785             toscaNode.setInterface_types(interfacesOperationsConverter.addInterfaceTypeElement(component, allGlobalInterfaceTypes));
786         }
787         final var dataTypesEither = applicationDataTypeCache.getAll(component.getModel());
788         if (dataTypesEither.isRight()) {
789             log.debug("Failed to fetch all data types :", dataTypesEither.right().value());
790             return Either.right(ToscaError.GENERAL_ERROR);
791         }
792         Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value();
793         List<InputDefinition> inputDef = component.getInputs();
794         interfacesOperationsConverter.addInterfaceDefinitionElement(component, toscaNodeType, dataTypes, isAssociatedComponent);
795         final var toscaAttributeMap = convertToToscaAttributes(component.getAttributes(), dataTypes);
796         if (!toscaAttributeMap.isEmpty()) {
797             toscaNodeType.setAttributes(toscaAttributeMap);
798         }
799         final var mergedProperties = convertInputsToProperties(dataTypes, inputDef, component.getUniqueId());
800         if (CollectionUtils.isNotEmpty(component.getProperties())) {
801             List<PropertyDefinition> properties = component.getProperties();
802             Map<String, ToscaProperty> convertedProperties = properties.stream()
803                 .map(propertyDefinition -> resolvePropertyValueFromInput(propertyDefinition, component.getInputs()))
804                 .collect(Collectors.toMap(PropertyDataDefinition::getName,
805                     property -> propertyConvertor.convertProperty(dataTypes, property, PropertyConvertor.PropertyType.PROPERTY)));
806             // merge component properties and inputs properties
807             convertedProperties.forEach((k, v) -> mergedProperties.putIfAbsent(k, v));
808         }
809         if (MapUtils.isNotEmpty(mergedProperties)) {
810             toscaNodeType.setProperties(mergedProperties);
811         }
812         /* convert private data_types */
813         List<DataTypeDefinition> privateDataTypes = component.getDataTypes();
814         if (CollectionUtils.isNotEmpty(privateDataTypes)) {
815             Map<String, ToscaDataType> toscaDataTypeMap = new HashMap<>();
816             for (DataTypeDefinition dataType : privateDataTypes) {
817                 log.debug("Emitting private data type: component.name={} dataType.name={}",
818                     component.getNormalizedName(), dataType.getName());
819                 ToscaDataType toscaDataType = new ToscaDataType();
820                 toscaDataType.setDerived_from(dataType.getDerivedFromName());
821                 toscaDataType.setDescription(dataType.getDescription());
822                 toscaDataType.setVersion(dataType.getVersion());
823                 if (CollectionUtils.isNotEmpty(dataType.getProperties())) {
824                     toscaDataType.setProperties(dataType.getProperties().stream()
825                         .collect(Collectors.toMap(
826                             PropertyDataDefinition::getName,
827                             s -> propertyConvertor.convertProperty(dataTypes, s, PropertyType.PROPERTY),
828                             (toscaPropertyTobeValidated, toscaProperty) -> validateToscaProperty(privateDataTypes, toscaPropertyTobeValidated,
829                                 toscaProperty)
830                         )));
831                 }
832                 toscaDataTypeMap.put(dataType.getName(), toscaDataType);
833             }
834             toscaNode.setData_types(toscaDataTypeMap);
835         }
836
837         // Extracted to method for code reuse
838         return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes);
839     }
840
841     private ToscaProperty validateToscaProperty(final List<DataTypeDefinition> privateDataTypes, final ToscaProperty toscaPropertyTobeValidated,
842                                                 final ToscaProperty toscaProperty) {
843         final Optional<DataTypeDefinition> match = privateDataTypes.stream()
844             .filter(dataType -> dataType.getName().equals(toscaPropertyTobeValidated.getType())).findFirst();
845         return match.isPresent() ? toscaPropertyTobeValidated : toscaProperty;
846     }
847
848     private Map<String, ToscaAttribute> convertToToscaAttributes(final List<AttributeDefinition> attributeList,
849                                                                  final Map<String, DataTypeDefinition> dataTypes) {
850         if (CollectionUtils.isEmpty(attributeList)) {
851             return Collections.emptyMap();
852         }
853         final AttributeConverter converter = new AttributeConverter(dataTypes);
854         final Map<String, ToscaAttribute> toscaAttributeMap = new HashMap<>();
855         for (final AttributeDefinition attributeDefinition : attributeList) {
856             toscaAttributeMap.put(attributeDefinition.getName(), converter.convert(attributeDefinition));
857         }
858         return toscaAttributeMap;
859     }
860
861     private Either<ToscaTemplate, ToscaError> convertReqCapAndTypeName(Map<String, Component> componentsCache,
862                                                                        Component component, ToscaTemplate toscaNode,
863                                                                        Map<String, ToscaNodeType> nodeTypes,
864                                                                        ToscaNodeType toscaNodeType,
865                                                                        Map<String, DataTypeDefinition> dataTypes) {
866         Either<ToscaNodeType, ToscaError> capabilities = convertCapabilities(componentsCache, component, toscaNodeType,
867             dataTypes);
868         if (capabilities.isRight()) {
869             return Either.right(capabilities.right().value());
870         }
871         toscaNodeType = capabilities.left().value();
872         log.debug("Capabilities converted for {}", component.getUniqueId());
873
874         Either<ToscaNodeType, ToscaError> requirements = capabilityRequirementConverter
875             .convertRequirements(componentsCache, component, toscaNodeType);
876         if (requirements.isRight()) {
877             return Either.right(requirements.right().value());
878         }
879         toscaNodeType = requirements.left().value();
880         log.debug("Requirements converted for {}", component.getUniqueId());
881
882         String toscaResourceName;
883         switch (component.getComponentType()) {
884             case RESOURCE:
885                 toscaResourceName = ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition()
886                     .getMetadataDataDefinition()).getToscaResourceName();
887                 break;
888             case SERVICE:
889                 toscaResourceName = SERVICE_NODE_TYPE_PREFIX
890                     + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName();
891                 break;
892             default:
893                 log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType());
894                 return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE);
895         }
896
897         nodeTypes.put(toscaResourceName, toscaNodeType);
898         toscaNode.setNode_types(nodeTypes);
899         log.debug("finish convert node type for {}", component.getUniqueId());
900         return Either.left(toscaNode);
901     }
902
903     private Either<Map<String, ToscaNodeTemplate>, ToscaError> convertNodeTemplates(final Component component,
904                                                                                     final Map<String, Component> componentCache,
905                                                                                     final Map<String, DataTypeDefinition> dataTypes,
906                                                                                     final ToscaTopolgyTemplate topologyTemplate) {
907
908         final Map<String, List<ComponentInstanceProperty>> componentInstancesProperties = component.getComponentInstancesProperties();
909         final Map<String, List<ComponentInstanceAttribute>> componentInstancesAttributes = component.getComponentInstancesAttributes();
910         final Map<String, List<ComponentInstanceInput>> componentInstancesInputs = component.getComponentInstancesInputs();
911         final Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces = component.getComponentInstancesInterfaces();
912         final List<RequirementCapabilityRelDef> componentInstancesRelations = component.getComponentInstancesRelations();
913
914         Either<Map<String, ToscaNodeTemplate>, ToscaError> convertNodeTemplatesRes = null;
915         log.debug("start convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType());
916         final Map<String, ToscaNodeTemplate> nodeTemplates = new HashMap<>();
917
918         Map<String, ToscaGroupTemplate> groupsMap = null;
919         for (final ComponentInstance componentInstance : component.getComponentInstances()) {
920             ToscaNodeTemplate nodeTemplate = new ToscaNodeTemplate();
921             if (MapUtils.isNotEmpty(componentInstance.getToscaArtifacts())) {
922                 nodeTemplate.setArtifacts(convertToNodeTemplateArtifacts(componentInstance.getToscaArtifacts()));
923             }
924             if (componentInstance.getMinOccurrences() != null && componentInstance.getMaxOccurrences() != null) {
925                 List<Object> occur = new ArrayList<>();
926                 occur.add(parseToIntIfPossible(componentInstance.getMinOccurrences()));
927                 occur.add(parseToIntIfPossible(componentInstance.getMaxOccurrences()));
928                 nodeTemplate.setOccurrences(occur);
929             }
930             if (componentInstance.getInstanceCount() != null) {
931                 ObjectMapper objectMapper = new ObjectMapper();
932                 Object obj = convertToToscaObject(componentInstance.getInstanceCount());
933                 if (obj != null) {
934                     Map<String, String> map = objectMapper.convertValue(obj, Map.class);
935                     nodeTemplate.setInstance_count(map);
936                 }
937             }
938             nodeTemplate.setType(componentInstance.getToscaComponentName());
939             nodeTemplate.setDirectives(componentInstance.getDirectives());
940             NodeFilter nodeFilter = convertToNodeTemplateNodeFilterComponent(componentInstance.getNodeFilter());
941             if (nodeFilter != null && nodeFilter.hasData()) {
942                 nodeTemplate.setNode_filter(nodeFilter);
943             }
944             final Either<Component, Boolean> originComponentRes = capabilityRequirementConverter
945                 .getOriginComponent(componentCache, componentInstance);
946             if (originComponentRes.isRight()) {
947                 convertNodeTemplatesRes = Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR);
948                 break;
949             }
950             final Either<ToscaNodeTemplate, ToscaError> requirements = convertComponentInstanceRequirements(component, componentInstance,
951                 componentInstancesRelations, nodeTemplate, originComponentRes.left().value(), componentCache);
952             if (requirements.isRight()) {
953                 convertNodeTemplatesRes = Either.right(requirements.right().value());
954                 break;
955             }
956             final String instanceUniqueId = componentInstance.getUniqueId();
957             log.debug("Component instance Requirements converted for instance {}", instanceUniqueId);
958
959             nodeTemplate = requirements.left().value();
960
961             final Component originalComponent = componentCache.get(componentInstance.getActualComponentUid());
962
963             if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) {
964                 final Component componentOfProxy = componentCache.get(componentInstance.getComponentUid());
965                 nodeTemplate.setMetadata(convertMetadata(componentOfProxy, true, componentInstance));
966             } else {
967                 nodeTemplate.setMetadata(convertMetadata(originalComponent, true, componentInstance));
968             }
969
970             final Either<ToscaNodeTemplate, ToscaError> capabilities =
971                 capabilityRequirementConverter.convertComponentInstanceCapabilities(componentInstance, dataTypes, nodeTemplate);
972             if (capabilities.isRight()) {
973                 convertNodeTemplatesRes = Either.right(capabilities.right().value());
974                 break;
975             }
976             log.debug("Component instance Capabilities converted for instance {}", instanceUniqueId);
977
978             nodeTemplate = capabilities.left().value();
979             final Map<String, Object> props = new HashMap<>();
980             final Map<String, Object> attribs = new HashMap<>();
981
982             if (originalComponent.getComponentType() == ComponentTypeEnum.RESOURCE) {
983                 // Adds the properties of parent component to map
984                 addPropertiesOfParentComponent(dataTypes, originalComponent, props);
985                 addAttributesOfParentComponent(originalComponent, attribs);
986             }
987
988             if (null != componentInstancesProperties && componentInstancesProperties.containsKey(instanceUniqueId)) {
989                 addPropertiesOfComponentInstance(componentInstancesProperties, dataTypes, instanceUniqueId, props);
990             }
991             if (null != componentInstancesAttributes && componentInstancesAttributes.containsKey(instanceUniqueId)) {
992                 addAttributesOfComponentInstance(componentInstancesAttributes, instanceUniqueId, attribs);
993             }
994
995             if (componentInstancesInputs != null
996                 && componentInstancesInputs.containsKey(instanceUniqueId)
997                 && !isComponentOfTypeServiceProxy(componentInstance)) {
998                 //For service proxy the inputs are already handled under instance properties above
999                 addComponentInstanceInputs(dataTypes, componentInstancesInputs, instanceUniqueId, props);
1000             }
1001
1002             //M3[00001] - NODE TEMPLATE INTERFACES  - START
1003             handleInstanceInterfaces(componentInstanceInterfaces, componentInstance, dataTypes, nodeTemplate, instanceUniqueId, component);
1004             //M3[00001] - NODE TEMPLATE INTERFACES  - END
1005             if (MapUtils.isNotEmpty(props)) {
1006                 nodeTemplate.setProperties(props);
1007             }
1008             if (MapUtils.isNotEmpty(attribs)) {
1009                 nodeTemplate.setAttributes(attribs);
1010             }
1011
1012             final List<GroupInstance> groupInstances = componentInstance.getGroupInstances();
1013             if (CollectionUtils.isNotEmpty(groupInstances)) {
1014                 if (groupsMap == null) {
1015                     groupsMap = new HashMap<>();
1016                 }
1017                 for (final GroupInstance groupInst : groupInstances) {
1018                     if (CollectionUtils.isNotEmpty(groupInst.getArtifacts())) {
1019                         groupsMap.put(groupInst.getName(), groupExportParser.getToscaGroupTemplate(groupInst, componentInstance.getInvariantName()));
1020                     }
1021                 }
1022             }
1023
1024             nodeTemplates.put(componentInstance.getName(), nodeTemplate);
1025         }
1026         if (groupsMap != null) {
1027             log.debug("instance groups added");
1028             topologyTemplate.addGroups(groupsMap);
1029         }
1030         if (component.getComponentType() == ComponentTypeEnum.SERVICE && isNotEmpty(
1031             ((Service) component).getForwardingPaths())) {
1032             log.debug("Starting converting paths for component {}, name {}", component.getUniqueId(), component.getName());
1033             ForwardingPathToscaUtil
1034                 .addForwardingPaths((Service) component, nodeTemplates, capabilityRequirementConverter, componentCache, toscaOperationFacade);
1035             log.debug("Finished converting paths for component {}, name {}", component.getUniqueId(), component.getName());
1036         }
1037         if (convertNodeTemplatesRes == null) {
1038             convertNodeTemplatesRes = Either.left(nodeTemplates);
1039         }
1040         log.debug("finish convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType());
1041         return convertNodeTemplatesRes;
1042     }
1043
1044     private Object convertToToscaObject(String value) {
1045         try {
1046             ToscaMapValueConverter mapConverterInst = ToscaMapValueConverter.getInstance();
1047             JsonParser jsonParser = new JsonParser();
1048             StringReader reader = new StringReader(value);
1049             JsonReader jsonReader = new JsonReader(reader);
1050             jsonReader.setLenient(true);
1051             JsonElement jsonElement = jsonParser.parse(jsonReader);
1052             if (jsonElement.isJsonObject()) {
1053                 JsonObject jsonObj = jsonElement.getAsJsonObject();
1054                 if (jsonObj.entrySet().size() == 1 && jsonObj.has(ToscaFunctions.GET_INPUT.getFunctionName())) {
1055                     return mapConverterInst.handleComplexJsonValue(jsonElement);
1056                 }
1057             }
1058             return null;
1059         } catch (Exception e) {
1060             log.debug("convertToToscaValue failed to parse json value :", e);
1061             return null;
1062         }
1063     }
1064
1065     private Object parseToIntIfPossible(final String value) {
1066         final Integer intValue = Ints.tryParse(value);
1067         return intValue == null ? value : intValue;
1068     }
1069
1070     private void handleInstanceInterfaces(
1071         Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces,
1072         ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate,
1073         String instanceUniqueId,
1074         Component parentComponent) {
1075
1076         if (MapUtils.isEmpty(componentInstanceInterfaces)
1077             || !componentInstanceInterfaces.containsKey(instanceUniqueId)) {
1078             nodeTemplate.setInterfaces(null);
1079             return;
1080         }
1081
1082         final List<ComponentInstanceInterface> currServiceInterfaces =
1083             componentInstanceInterfaces.get(instanceUniqueId);
1084
1085         final Map<String, InterfaceDefinition> tmpInterfaces = new HashMap<>();
1086         currServiceInterfaces.forEach(instInterface -> tmpInterfaces.put(instInterface
1087             .getUniqueId(), instInterface));
1088
1089         final Map<String, Object> interfaceMap = interfacesOperationsConverter
1090             .getInterfacesMap(parentComponent, componentInstance, tmpInterfaces, dataTypes, isComponentOfTypeServiceProxy(componentInstance),
1091                 isComponentOfTypeServiceProxy(componentInstance));
1092
1093         interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
1094         nodeTemplate.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap);
1095     }
1096
1097     private boolean isComponentOfTypeServiceProxy(ComponentInstance componentInstance) {
1098         return Objects.nonNull(componentInstance.getOriginType())
1099             && componentInstance.getOriginType().getValue().equals("Service Proxy");
1100     }
1101
1102     private void addComponentInstanceInputs(Map<String, DataTypeDefinition> dataTypes,
1103                                             Map<String, List<ComponentInstanceInput>> componentInstancesInputs,
1104                                             String instanceUniqueId, Map<String, Object> props) {
1105
1106         List<ComponentInstanceInput> instanceInputsList = componentInstancesInputs.get(instanceUniqueId);
1107         if (instanceInputsList != null) {
1108             instanceInputsList.forEach(input -> {
1109                 Supplier<String> supplier = () -> input.getValue() != null && !Objects.isNull(input.getValue()) ? input.getValue()
1110                     : input.getDefaultValue();
1111                 propertyConvertor.convertAndAddValue(dataTypes, props, input, supplier);
1112             });
1113         }
1114     }
1115
1116     private void addPropertiesOfComponentInstance(final Map<String, List<ComponentInstanceProperty>> componentInstancesProperties,
1117                                                   final Map<String, DataTypeDefinition> dataTypes,
1118                                                   final String instanceUniqueId,
1119                                                   final Map<String, Object> props) {
1120
1121         if (isNotEmpty(componentInstancesProperties)) {
1122             componentInstancesProperties.get(instanceUniqueId)
1123                 // Converts and adds each value to property map
1124                 .forEach(prop -> propertyConvertor.convertAndAddValue(dataTypes, props, prop, prop::getValue));
1125         }
1126     }
1127
1128     private void addAttributesOfComponentInstance(final Map<String, List<ComponentInstanceAttribute>> componentInstancesAttributes,
1129                                                   final String instanceUniqueId,
1130                                                   final Map<String, Object> attribs) {
1131
1132         if (isNotEmpty(componentInstancesAttributes) && componentInstancesAttributes.containsKey(instanceUniqueId)) {
1133             componentInstancesAttributes.get(instanceUniqueId)
1134                 .forEach(attributeDefinition -> attributeConverter.convertAndAddValue(attribs, attributeDefinition));
1135         }
1136     }
1137
1138     private void addPropertiesOfParentComponent(Map<String, DataTypeDefinition> dataTypes,
1139                                                 Component componentOfInstance, Map<String, Object> props) {
1140
1141         List<PropertyDefinition> componentProperties = componentOfInstance.getProperties();
1142         if (isNotEmpty(componentProperties)) {
1143             componentProperties.stream()
1144                 // Filters out properties with empty default values
1145                 .filter(prop -> StringUtils.isNotEmpty(prop.getDefaultValue()))
1146                 // Converts and adds each value to property map
1147                 .forEach(prop -> propertyConvertor.convertAndAddValue(dataTypes, props, prop, prop::getDefaultValue));
1148         }
1149     }
1150
1151     private void addAttributesOfParentComponent(final Component componentOfInstance, final Map<String, Object> attribs) {
1152
1153         final List<AttributeDefinition> componentAttributes = componentOfInstance.getAttributes();
1154         if (isNotEmpty(componentAttributes)) {
1155             componentAttributes.stream()
1156                 // Filters out Attributes with empty default values
1157                 .filter(attrib -> StringUtils.isNotEmpty(attrib.getDefaultValue()))
1158                 // Converts and adds each value to attribute map
1159                 .forEach(attributeDefinition -> attributeConverter.convertAndAddValue(attribs, attributeDefinition));
1160         }
1161     }
1162
1163     private ToscaNodeType createNodeType(Component component) {
1164         ToscaNodeType toscaNodeType = new ToscaNodeType();
1165         if (ModelConverter.isAtomicComponent(component)) {
1166             if (((Resource) component).getDerivedFrom() != null) {
1167                 toscaNodeType.setDerived_from(((Resource) component).getDerivedFrom().get(0));
1168             }
1169             toscaNodeType.setDescription(component.getDescription());
1170         } else {
1171             String derivedFrom = null != component.getDerivedFromGenericType() ? component.getDerivedFromGenericType()
1172                 : NATIVE_ROOT;
1173             toscaNodeType.setDerived_from(derivedFrom);
1174         }
1175         return toscaNodeType;
1176     }
1177
1178     private Either<Map<String, Object>, ToscaError> createProxyInterfaceTypes(Component container) {
1179
1180         Map<String, Object> proxyInterfaceTypes = new HashMap<>();
1181         Either<Map<String, Object>, ToscaError> res = Either.left(proxyInterfaceTypes);
1182         List<ComponentInstance> componentInstances = container.getComponentInstances();
1183         if (CollectionUtils.isEmpty(componentInstances)) {
1184             return res;
1185         }
1186         Map<String, ComponentInstance> serviceProxyInstanceList = new HashMap<>();
1187         componentInstances.stream()
1188             .filter(this::isComponentOfTypeServiceProxy)
1189             .forEach(inst -> serviceProxyInstanceList.put(inst.getToscaComponentName(), inst));
1190         if (MapUtils.isEmpty(serviceProxyInstanceList)) {
1191             return res;
1192         }
1193         for (Entry<String, ComponentInstance> entryProxy : serviceProxyInstanceList.entrySet()) {
1194             Component serviceComponent;
1195             ComponentParametersView componentParametersView = new ComponentParametersView();
1196             componentParametersView.disableAll();
1197             componentParametersView.setIgnoreInterfaces(false);
1198             Either<Component, StorageOperationStatus> service = toscaOperationFacade
1199                 .getToscaElement(entryProxy.getValue().getSourceModelUid(), componentParametersView);
1200             if (service.isRight()) {
1201                 log.debug("Failed to fetch original service component with id {} for instance {}",
1202                     entryProxy.getValue().getSourceModelUid(), entryProxy.getValue().getName());
1203                 return Either.right(ToscaError.GENERAL_ERROR);
1204             } else {
1205                 serviceComponent = service.left().value();
1206             }
1207
1208             Either<Map<String, InterfaceDefinition>, StorageOperationStatus> lifecycleTypeEither =
1209                 interfaceLifecycleOperation.getAllInterfaceLifecycleTypes(serviceComponent.getModel());
1210             if (lifecycleTypeEither.isRight()) {
1211                 log.debug("Failed to retrieve global interface types :", lifecycleTypeEither.right().value());
1212                 return Either.right(ToscaError.GENERAL_ERROR);
1213             }
1214
1215             List<String> allGlobalInterfaceTypes = lifecycleTypeEither.left().value().values().stream()
1216                 .map(InterfaceDataDefinition::getType)
1217                 .collect(Collectors.toList());
1218             //Add interface types for local interfaces in the original service component for proxy
1219             Map<String, Object> localInterfaceTypes = interfacesOperationsConverter.addInterfaceTypeElement(serviceComponent,
1220                 allGlobalInterfaceTypes);
1221             if (MapUtils.isNotEmpty(localInterfaceTypes)) {
1222                 proxyInterfaceTypes.putAll(localInterfaceTypes);
1223             }
1224
1225         }
1226         return Either.left(proxyInterfaceTypes);
1227     }
1228
1229     private Either<Map<String, ToscaNodeType>, ToscaError> createProxyNodeTypes(Map<String, Component> componentCache,
1230                                                                                 Component container) {
1231
1232         Map<String, ToscaNodeType> nodeTypesMap = new HashMap<>();
1233         Either<Map<String, ToscaNodeType>, ToscaError> res = Either.left(nodeTypesMap);
1234
1235         List<ComponentInstance> componentInstances = container.getComponentInstances();
1236
1237         if (componentInstances == null || componentInstances.isEmpty()) {
1238             return res;
1239         }
1240         Map<String, ComponentInstance> serviceProxyInstanceList = new HashMap<>();
1241         List<ComponentInstance> proxyInst = componentInstances.stream()
1242             .filter(p -> p.getOriginType().name().equals(OriginTypeEnum.ServiceProxy.name()))
1243             .collect(Collectors.toList());
1244         if (proxyInst != null && !proxyInst.isEmpty()) {
1245             for (ComponentInstance inst : proxyInst) {
1246                 serviceProxyInstanceList.put(inst.getToscaComponentName(), inst);
1247             }
1248         }
1249
1250         if (serviceProxyInstanceList.isEmpty()) {
1251             return res;
1252         }
1253         Either<Resource, StorageOperationStatus> serviceProxyOrigin = toscaOperationFacade
1254             .getLatestByName("serviceProxy", null);
1255         if (serviceProxyOrigin.isRight()) {
1256             log.debug("Failed to fetch normative service proxy resource by tosca name, error {}",
1257                 serviceProxyOrigin.right().value());
1258             return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE);
1259         }
1260         Component origComponent = serviceProxyOrigin.left().value();
1261
1262         for (Entry<String, ComponentInstance> entryProxy : serviceProxyInstanceList.entrySet()) {
1263             Component serviceComponent = null;
1264             ComponentParametersView componentParametersView = new ComponentParametersView();
1265             componentParametersView.disableAll();
1266             componentParametersView.setIgnoreCategories(false);
1267             componentParametersView.setIgnoreProperties(false);
1268             componentParametersView.setIgnoreInputs(false);
1269             componentParametersView.setIgnoreInterfaces(false);
1270             componentParametersView.setIgnoreRequirements(false);
1271             Either<Component, StorageOperationStatus> service = toscaOperationFacade
1272                 .getToscaElement(entryProxy.getValue().getSourceModelUid(), componentParametersView);
1273             if (service.isRight()) {
1274                 log.debug("Failed to fetch resource with id {} for instance {}",
1275                     entryProxy.getValue().getSourceModelUid(), entryProxy.getValue().getName());
1276             } else {
1277                 serviceComponent = service.left().value();
1278             }
1279
1280             ToscaNodeType toscaNodeType = createProxyNodeType(componentCache, origComponent, serviceComponent,
1281                 entryProxy.getValue());
1282             nodeTypesMap.put(entryProxy.getKey(), toscaNodeType);
1283         }
1284
1285         return Either.left(nodeTypesMap);
1286     }
1287
1288     private void createServiceSubstitutionNodeTypes(final Map<String, Component> componentCache,
1289                                                     final Component container, final ToscaTemplate toscaNode) {
1290         final List<ComponentInstance> componentInstances = container.getComponentInstances();
1291
1292         if (CollectionUtils.isEmpty(componentInstances)) {
1293             return;
1294         }
1295         final List<ComponentInstance> serviceSubstitutionInstanceList = componentInstances.stream()
1296             .filter(p -> p.getOriginType().name().equals(OriginTypeEnum.ServiceSubstitution.name()))
1297             .collect(Collectors.toList());
1298         if (CollectionUtils.isNotEmpty(serviceSubstitutionInstanceList)) {
1299             for (ComponentInstance inst : serviceSubstitutionInstanceList) {
1300                 final Map<String, ToscaNodeType> nodeTypes =
1301                     toscaNode.getNode_types() == null ? new HashMap<>() : toscaNode.getNode_types();
1302                 convertInterfaceNodeType(new HashMap<>(), componentCache.get(inst.getSourceModelUid()), toscaNode,
1303                     nodeTypes, true);
1304             }
1305         }
1306     }
1307
1308     private ToscaNodeType createProxyNodeType(Map<String, Component> componentCache, Component origComponent,
1309                                               Component proxyComponent, ComponentInstance componentInstance) {
1310         ToscaNodeType toscaNodeType = new ToscaNodeType();
1311         String derivedFrom = ((Resource) origComponent).getToscaResourceName();
1312
1313         toscaNodeType.setDerived_from(derivedFrom);
1314         Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> dataTypesEither = applicationDataTypeCache.getAll(
1315             origComponent.getModel());
1316         if (dataTypesEither.isRight()) {
1317             log.debug("Failed to retrieve all data types {}", dataTypesEither.right().value());
1318         }
1319         Map<String, DataTypeDefinition> dataTypes = dataTypesEither.left().value();
1320         Map<String, ToscaCapability> capabilities = this.capabilityRequirementConverter
1321             .convertProxyCapabilities(componentCache, componentInstance, dataTypes);
1322
1323         if (MapUtils.isNotEmpty(capabilities)) {
1324             toscaNodeType.setCapabilities(capabilities);
1325         }
1326         List<Map<String, ToscaRequirement>> proxyNodeTypeRequirements = this.capabilityRequirementConverter
1327             .convertProxyRequirements(componentCache, componentInstance);
1328         if (CollectionUtils.isNotEmpty(proxyNodeTypeRequirements)) {
1329             toscaNodeType.setRequirements(proxyNodeTypeRequirements);
1330         }
1331         Optional<Map<String, ToscaProperty>> proxyProperties = getProxyNodeTypeProperties(proxyComponent, dataTypes);
1332         proxyProperties.ifPresent(toscaNodeType::setProperties);
1333
1334         Map<String, Object> interfaceMap = new HashMap<>();
1335         if (MapUtils.isEmpty(componentInstance.getInterfaces())) {
1336             final Optional<Map<String, Object>> proxyInterfaces = getProxyNodeTypeInterfaces(proxyComponent, dataTypes);
1337             if (proxyInterfaces.isPresent()) {
1338                 interfaceMap = proxyInterfaces.get();
1339             }
1340         } else {
1341             interfaceMap = interfacesOperationsConverter
1342                 .getInterfacesMapFromComponentInstance(proxyComponent, componentInstance, dataTypes, false, false);
1343
1344         }
1345         interfacesOperationsConverter.removeInterfacesWithoutOperations(interfaceMap);
1346         toscaNodeType.setInterfaces(MapUtils.isEmpty(interfaceMap) ? null : interfaceMap);
1347
1348         return toscaNodeType;
1349     }
1350
1351     private Either<ToscaNodeTemplate, ToscaError> convertComponentInstanceRequirements(Component component,
1352                                                                                        ComponentInstance componentInstance,
1353                                                                                        List<RequirementCapabilityRelDef> relations,
1354                                                                                        ToscaNodeTemplate nodeTypeTemplate,
1355                                                                                        Component originComponent,
1356                                                                                        Map<String, Component> componentCache) {
1357
1358         final List<RequirementCapabilityRelDef> requirementDefinitionList = filterRequirements(componentInstance,
1359             relations);
1360         if (isNotEmpty(requirementDefinitionList)) {
1361             try {
1362                 final List<Map<String, ToscaTemplateRequirement>> toscaRequirements = buildRequirements(component, componentInstance,
1363                     requirementDefinitionList, originComponent, componentCache);
1364                 if (!toscaRequirements.isEmpty()) {
1365                     nodeTypeTemplate.setRequirements(toscaRequirements);
1366                 }
1367             } catch (final Exception e) {
1368                 log.debug("Failed to convert component instance requirements for the component instance {}. ",
1369                     componentInstance.getName(), e);
1370                 return Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR);
1371             }
1372         }
1373         log.debug("Finished to convert requirements for the node type {} ", componentInstance.getName());
1374         return Either.left(nodeTypeTemplate);
1375     }
1376
1377     private List<Map<String, ToscaTemplateRequirement>> buildRequirements(final Component component,
1378                                                                           final ComponentInstance componentInstance,
1379                                                                           final List<RequirementCapabilityRelDef> filteredRelations,
1380                                                                           final Component originComponent,
1381                                                                           final Map<String, Component> componentCache)
1382         throws ToscaExportException {
1383
1384         final List<Map<String, ToscaTemplateRequirement>> toscaRequirements = new ArrayList<>();
1385         for (RequirementCapabilityRelDef relationshipDefinition : filteredRelations) {
1386             final Map<String, ToscaTemplateRequirement> toscaTemplateRequirementMap =
1387                 buildRequirement(componentInstance, originComponent, component.getComponentInstances(), relationshipDefinition, componentCache);
1388             toscaRequirements.add(toscaTemplateRequirementMap);
1389         }
1390
1391         return toscaRequirements;
1392     }
1393
1394     private List<RequirementCapabilityRelDef> filterRequirements(ComponentInstance componentInstance,
1395                                                                  List<RequirementCapabilityRelDef> relations) {
1396         return relations.stream()
1397             .filter(p -> componentInstance.getUniqueId().equals(p.getFromNode())).collect(Collectors.toList());
1398     }
1399
1400     private Map<String, ToscaTemplateRequirement> buildRequirement(final ComponentInstance fromInstance,
1401                                                                    final Component fromOriginComponent,
1402                                                                    final List<ComponentInstance> instancesList,
1403                                                                    final RequirementCapabilityRelDef relationshipDefinition,
1404                                                                    final Map<String, Component> componentCache)
1405         throws ToscaExportException {
1406
1407         final Map<String, List<RequirementDefinition>> reqMap = fromOriginComponent.getRequirements();
1408         final CapabilityRequirementRelationship capabilityRequirementRelationship = relationshipDefinition
1409             .getRelationships().get(0);
1410         final RelationshipInfo relationshipInfo = capabilityRequirementRelationship.getRelation();
1411
1412         final ComponentInstance toInstance = instancesList.stream()
1413             .filter(i -> relationshipDefinition.getToNode().equals(i.getUniqueId()))
1414             .findFirst().orElse(null);
1415         if (toInstance == null) {
1416             final String errorMsg = String
1417                 .format("Failed to find a relation from the node %s to the node %s", fromInstance.getName(),
1418                     relationshipDefinition.getToNode());
1419             log.debug(errorMsg);
1420             throw new ToscaExportException(errorMsg);
1421         }
1422         final Optional<RequirementDefinition> reqOpt =
1423             findRequirement(fromOriginComponent, reqMap, relationshipInfo, fromInstance.getUniqueId());
1424         if (reqOpt.isEmpty()) {
1425             final String errorMsg = String
1426                 .format("Failed to find a requirement with uniqueId %s on a component with uniqueId %s",
1427                     relationshipInfo.getRequirementUid(), fromOriginComponent.getUniqueId());
1428             log.debug(errorMsg);
1429             throw new ToscaExportException(errorMsg);
1430         }
1431         final ComponentParametersView filter = new ComponentParametersView(true);
1432         filter.setIgnoreComponentInstances(false);
1433         filter.setIgnoreCapabilities(false);
1434         filter.setIgnoreGroups(false);
1435         final Either<Component, StorageOperationStatus> getOriginRes =
1436             toscaOperationFacade.getToscaElement(toInstance.getActualComponentUid(), filter);
1437         if (getOriginRes.isRight()) {
1438             final String errorMsg = String.format(
1439                 "Failed to build substituted name for the requirement %s. "
1440                     + "Failed to get an origin component with uniqueId %s",
1441                 reqOpt.get().getName(), toInstance.getActualComponentUid());
1442             log.debug(errorMsg);
1443             throw new ToscaExportException(errorMsg);
1444         }
1445         final Component toOriginComponent = getOriginRes.left().value();
1446         Optional<CapabilityDefinition> capOpt = toOriginComponent.getCapabilities().get(reqOpt.get().getCapability()).stream()
1447             .filter(c -> isCapabilityBelongToRelation(relationshipInfo, c)).findFirst();
1448         if (capOpt.isEmpty()) {
1449             capOpt = findCapability(relationshipInfo, toOriginComponent, fromOriginComponent, reqOpt.get());
1450             if (capOpt.isEmpty()) {
1451                 final String errorMsg = String
1452                     .format("Failed to find a capability with name %s on a component with uniqueId %s",
1453                         relationshipInfo.getCapability(), fromOriginComponent.getUniqueId());
1454                 log.debug(errorMsg);
1455                 throw new ToscaExportException(errorMsg);
1456             }
1457         }
1458         return buildRequirement(fromOriginComponent, toOriginComponent, capOpt.get(), reqOpt.get(),
1459             capabilityRequirementRelationship, toInstance, componentCache);
1460     }
1461
1462     private boolean isCapabilityBelongToRelation(RelationshipInfo reqAndRelationshipPair,
1463                                                  CapabilityDefinition capability) {
1464         return capability.getName().equals(reqAndRelationshipPair.getCapability()) && (capability.getOwnerId() != null
1465             && capability.getOwnerId().equals(reqAndRelationshipPair.getCapabilityOwnerId()));
1466     }
1467
1468     private Optional<CapabilityDefinition> findCapability(RelationshipInfo reqAndRelationshipPair,
1469                                                           Component toOriginComponent, Component fromOriginComponent,
1470                                                           RequirementDefinition requirement) {
1471         Optional<CapabilityDefinition> cap = toOriginComponent.getCapabilities().get(requirement.getCapability())
1472             .stream().filter(c -> c.getType().equals(requirement.getCapability())).findFirst();
1473         if (!cap.isPresent()) {
1474             log.debug("Failed to find a capability with name {} on a component with uniqueId {}",
1475                 reqAndRelationshipPair.getCapability(), fromOriginComponent.getUniqueId());
1476         }
1477         return cap;
1478     }
1479
1480     private Map<String, ToscaTemplateRequirement> buildRequirement(final Component fromOriginComponent,
1481                                                                    final Component toOriginComponent,
1482                                                                    final CapabilityDefinition capability,
1483                                                                    final RequirementDefinition requirement,
1484                                                                    final CapabilityRequirementRelationship capabilityRequirementRelationship,
1485                                                                    final ComponentInstance toInstance,
1486                                                                    final Map<String, Component> componentCache)
1487         throws ToscaExportException {
1488
1489         List<String> reducedPath = capability.getPath();
1490         if (capability.getOwnerId() != null) {
1491             reducedPath = capabilityRequirementConverter
1492                 .getReducedPathByOwner(capability.getPath(), capability.getOwnerId());
1493         }
1494         final RelationshipInfo relationshipInfo = capabilityRequirementRelationship.getRelation();
1495         final Either<String, Boolean> capabilityNameEither = capabilityRequirementConverter.buildSubstitutedName(componentCache,
1496             toOriginComponent, reducedPath, relationshipInfo.getCapability(), capability.getPreviousName(), capability.getExternalName());
1497         if (capabilityNameEither.isRight()) {
1498             final String errorMsg = String.format(
1499                 "Failed to build a substituted capability name for the capability with name %s on a component with uniqueId %s",
1500                 capabilityRequirementRelationship.getCapability(), toOriginComponent.getUniqueId());
1501             log.debug(
1502                 errorMsg);
1503             throw new ToscaExportException(errorMsg);
1504         }
1505         final Either<String, Boolean> requirementNameEither = capabilityRequirementConverter
1506             .buildSubstitutedName(componentCache, fromOriginComponent,
1507                 requirement.getPath(), relationshipInfo.getRequirement(), requirement.getPreviousName(), requirement.getExternalName());
1508         if (requirementNameEither.isRight()) {
1509             final String errorMsg = String.format("Failed to build a substituted requirement name for the requirement "
1510                     + "with name %s on a component with uniqueId %s",
1511                 capabilityRequirementRelationship.getRequirement(), fromOriginComponent.getUniqueId());
1512             log.debug(errorMsg);
1513             throw new ToscaExportException(errorMsg);
1514         }
1515         final ToscaTemplateRequirement toscaRequirement = new ToscaTemplateRequirement();
1516         final Map<String, ToscaTemplateRequirement> toscaReqMap = new HashMap<>();
1517         toscaRequirement.setNode(toInstance.getName());
1518         toscaRequirement.setCapability(capabilityNameEither.left().value());
1519         if (isNotEmpty(capabilityRequirementRelationship.getOperations())) {
1520             toscaRequirement.setRelationship(new ToscaRelationshipBuilder().from(capabilityRequirementRelationship));
1521         }
1522         toscaReqMap.put(requirementNameEither.left().value(), toscaRequirement);
1523         return toscaReqMap;
1524     }
1525
1526     private Optional<RequirementDefinition> findRequirement(Component fromOriginComponent,
1527                                                             Map<String, List<RequirementDefinition>> reqMap,
1528                                                             RelationshipInfo reqAndRelationshipPair,
1529                                                             String fromInstanceId) {
1530         for (List<RequirementDefinition> reqList : reqMap.values()) {
1531             Optional<RequirementDefinition> reqOpt = reqList.stream().filter(
1532                     r -> isRequirementBelongToRelation(fromOriginComponent, reqAndRelationshipPair, r, fromInstanceId))
1533                 .findFirst();
1534             if (reqOpt.isPresent()) {
1535                 return reqOpt;
1536             }
1537         }
1538         return Optional.empty();
1539     }
1540
1541     /**
1542      * Allows detecting the requirement belonging to the received relationship The detection logic is: A requirement belongs to a relationship IF
1543      * 1.The name of the requirement equals to the "requirement" field of the relation; AND 2. In case of a non-atomic resource, OwnerId of the
1544      * requirement equals to requirementOwnerId of the relation OR uniqueId of toInstance equals to capabilityOwnerId of the relation
1545      */
1546     private boolean isRequirementBelongToRelation(Component originComponent, RelationshipInfo reqAndRelationshipPair,
1547                                                   RequirementDefinition requirement, String fromInstanceId) {
1548         if (!StringUtils.equals(requirement.getName(), reqAndRelationshipPair.getRequirement())) {
1549             log.debug("Failed to find a requirement with name {} and  reqAndRelationshipPair {}", requirement.getName(),
1550                 reqAndRelationshipPair.getRequirement());
1551             return false;
1552         }
1553         return ModelConverter.isAtomicComponent(originComponent) || isRequirementBelongToOwner(reqAndRelationshipPair, requirement, fromInstanceId,
1554             originComponent);
1555     }
1556
1557     private boolean isRequirementBelongToOwner(RelationshipInfo reqAndRelationshipPair, RequirementDefinition requirement, String fromInstanceId,
1558                                                Component originComponent) {
1559         return StringUtils.equals(requirement.getOwnerId(), reqAndRelationshipPair.getRequirementOwnerId()) || (
1560             isCvfc(originComponent) && StringUtils.equals(fromInstanceId, reqAndRelationshipPair.getRequirementOwnerId()) || StringUtils
1561                 .equals(requirement.getOwnerId(), originComponent.getUniqueId()));
1562     }
1563
1564     private boolean isCvfc(Component component) {
1565         return component.getComponentType() == ComponentTypeEnum.RESOURCE && ((Resource) component).getResourceType() == ResourceTypeEnum.CVFC;
1566     }
1567
1568     private Either<Map<String, String[]>, ToscaError> convertSubstitutionMappingCapabilities(final Component component,
1569                                                                                              final Map<String, Component> componentCache) {
1570         Either<Map<String, String[]>, ToscaError> toscaCapabilitiesRes =
1571             capabilityRequirementConverter.convertSubstitutionMappingCapabilities(componentCache, component);
1572         if (toscaCapabilitiesRes.isRight()) {
1573             log.debug("Failed convert capabilities for the component {}. ", component.getName());
1574             return Either.right(toscaCapabilitiesRes.right().value());
1575         }
1576         if (isNotEmpty(toscaCapabilitiesRes.left().value())) {
1577             log.debug("Finish convert capabilities for the component {}. ", component.getName());
1578             return Either.left(toscaCapabilitiesRes.left().value());
1579         }
1580         log.debug("Finished to convert capabilities for the component {}. ", component.getName());
1581
1582         return Either.left(Collections.emptyMap());
1583     }
1584
1585     private Either<ToscaNodeType, ToscaError> convertCapabilities(Map<String, Component> componentsCache, Component component, ToscaNodeType nodeType,
1586                                                                   Map<String, DataTypeDefinition> dataTypes) {
1587         Map<String, ToscaCapability> toscaCapabilities = capabilityRequirementConverter.convertCapabilities(componentsCache, component, dataTypes);
1588         if (!toscaCapabilities.isEmpty()) {
1589             nodeType.setCapabilities(toscaCapabilities);
1590         }
1591         log.debug("Finish convert Capabilities for node type");
1592         return Either.left(nodeType);
1593     }
1594
1595     private Map<String, ToscaTemplateArtifact> convertToNodeTemplateArtifacts(Map<String, ToscaArtifactDataDefinition> artifacts) {
1596         if (artifacts == null) {
1597             return null;
1598         }
1599         Map<String, ToscaTemplateArtifact> arts = new HashMap<>();
1600         for (Map.Entry<String, ToscaArtifactDataDefinition> entry : artifacts.entrySet()) {
1601             ToscaTemplateArtifact artifact = new ToscaTemplateArtifact();
1602             artifact.setFile(entry.getValue().getFile());
1603             artifact.setType(entry.getValue().getType());
1604             artifact.setProperties(entry.getValue().getProperties());
1605             arts.put(entry.getKey(), artifact);
1606         }
1607         return arts;
1608     }
1609
1610     private NodeFilter convertToNodeTemplateNodeFilterComponent(CINodeFilterDataDefinition inNodeFilter) {
1611         if (inNodeFilter == null) {
1612             return null;
1613         }
1614         NodeFilter nodeFilter = new NodeFilter();
1615         ListDataDefinition<RequirementNodeFilterCapabilityDataDefinition> origCapabilities = inNodeFilter.getCapabilities();
1616         ListDataDefinition<RequirementNodeFilterPropertyDataDefinition> origProperties = inNodeFilter.getProperties();
1617         List<Map<String, CapabilityFilter>> capabilitiesCopy = new ArrayList<>();
1618         List<Map<String, List<Object>>> propertiesCopy = new ArrayList<>();
1619         copyNodeFilterCapabilitiesTemplate(origCapabilities, capabilitiesCopy);
1620         copyNodeFilterProperties(origProperties, propertiesCopy);
1621         if (CollectionUtils.isNotEmpty(capabilitiesCopy)) {
1622             nodeFilter.setCapabilities(capabilitiesCopy);
1623         }
1624         if (CollectionUtils.isNotEmpty(propertiesCopy)) {
1625             nodeFilter.setProperties(propertiesCopy);
1626         }
1627         nodeFilter.setTosca_id(cloneToscaId(inNodeFilter.getTosca_id()));
1628         nodeFilter = (NodeFilter) cloneObjectFromYml(nodeFilter, NodeFilter.class);
1629         return nodeFilter;
1630     }
1631
1632     private NodeFilter convertToSubstitutionFilterComponent(final SubstitutionFilterDataDefinition substitutionFilterDataDefinition) {
1633         if (substitutionFilterDataDefinition == null) {
1634             return null;
1635         }
1636         NodeFilter nodeFilter = new NodeFilter();
1637         ListDataDefinition<RequirementSubstitutionFilterPropertyDataDefinition> origProperties = substitutionFilterDataDefinition.getProperties();
1638         List<Map<String, List<Object>>> propertiesCopy = new ArrayList<>();
1639         copySubstitutionFilterProperties(origProperties, propertiesCopy);
1640         if (CollectionUtils.isNotEmpty(propertiesCopy)) {
1641             nodeFilter.setProperties(propertiesCopy);
1642         }
1643         nodeFilter.setTosca_id(cloneToscaId(substitutionFilterDataDefinition.getTosca_id()));
1644         return (NodeFilter) cloneObjectFromYml(nodeFilter, NodeFilter.class);
1645     }
1646
1647     private Object cloneToscaId(Object toscaId) {
1648         return Objects.isNull(toscaId) ? null : cloneObjectFromYml(toscaId, toscaId.getClass());
1649     }
1650
1651     private Object cloneObjectFromYml(Object objToClone, Class classOfObj) {
1652         String objectAsYml = yamlUtil.objectToYaml(objToClone);
1653         return yamlUtil.yamlToObject(objectAsYml, classOfObj);
1654     }
1655
1656     private void copyNodeFilterCapabilitiesTemplate(ListDataDefinition<RequirementNodeFilterCapabilityDataDefinition> origCapabilities,
1657                                                     List<Map<String, CapabilityFilter>> capabilitiesCopy) {
1658         if (origCapabilities == null || origCapabilities.getListToscaDataDefinition() == null || origCapabilities.getListToscaDataDefinition()
1659             .isEmpty()) {
1660             return;
1661         }
1662         for (RequirementNodeFilterCapabilityDataDefinition capability : origCapabilities.getListToscaDataDefinition()) {
1663             Map<String, CapabilityFilter> capabilityFilterCopyMap = new HashMap<>();
1664             CapabilityFilter capabilityFilter = new CapabilityFilter();
1665             List<Map<String, List<Object>>> propertiesCopy = new ArrayList<>();
1666             copyNodeFilterProperties(capability.getProperties(), propertiesCopy);
1667             capabilityFilter.setProperties(propertiesCopy);
1668             capabilityFilterCopyMap.put(capability.getName(), capabilityFilter);
1669             capabilitiesCopy.add(capabilityFilterCopyMap);
1670         }
1671     }
1672
1673     private void copyNodeFilterProperties(ListDataDefinition<RequirementNodeFilterPropertyDataDefinition> origProperties,
1674                                           List<Map<String, List<Object>>> propertiesCopy) {
1675         if (origProperties == null || origProperties.getListToscaDataDefinition() == null || origProperties.isEmpty()) {
1676             return;
1677         }
1678         Map<String, List<Object>> propertyMapCopy = new HashMap<>();
1679         for (RequirementNodeFilterPropertyDataDefinition propertyDataDefinition : origProperties.getListToscaDataDefinition()) {
1680             for (String propertyInfoEntry : propertyDataDefinition.getConstraints()) {
1681                 Map<String, List<Object>> propertyValObj = new YamlUtil().yamlToObject(propertyInfoEntry, Map.class);
1682                 String propertyName = propertyDataDefinition.getName();
1683                 if (propertyMapCopy.containsKey(propertyName)) {
1684                     addPropertyConstraintValueToList(propertyName, propertyValObj, propertyMapCopy.get(propertyName));
1685                 } else {
1686                     if (propertyName != null) {
1687                         List<Object> propsList = new ArrayList<>();
1688                         addPropertyConstraintValueToList(propertyName, propertyValObj, propsList);
1689                         propertyMapCopy.put(propertyName, propsList);
1690                     } else {
1691                         propertyMapCopy.putAll(propertyValObj);
1692                     }
1693                 }
1694             }
1695         }
1696         propertyMapCopy.entrySet().stream().forEach(entry -> addCalculatedConstraintsIntoPropertiesList(propertiesCopy, entry));
1697     }
1698
1699     private void copySubstitutionFilterProperties(final ListDataDefinition<RequirementSubstitutionFilterPropertyDataDefinition> origProperties,
1700                                                   final List<Map<String, List<Object>>> propertiesCopy) {
1701         if (origProperties == null || origProperties.getListToscaDataDefinition() == null || origProperties.isEmpty()) {
1702             return;
1703         }
1704         final Map<String, List<Object>> propertyMapCopy = new HashMap<>();
1705         for (final RequirementSubstitutionFilterPropertyDataDefinition propertyDataDefinition : origProperties.getListToscaDataDefinition()) {
1706             for (final String propertyInfoEntry : propertyDataDefinition.getConstraints()) {
1707                 final Map<String, List<Object>> propertyValObj = new YamlUtil().yamlToObject(propertyInfoEntry, Map.class);
1708                 final String propertyName = propertyDataDefinition.getName();
1709                 if (propertyMapCopy.containsKey(propertyName)) {
1710                     addPropertyConstraintValueToList(propertyName, propertyValObj, propertyMapCopy.get(propertyName));
1711                 } else {
1712                     if (propertyName != null) {
1713                         final List<Object> propsList = new ArrayList<>();
1714                         addPropertyConstraintValueToList(propertyName, propertyValObj, propsList);
1715                         propertyMapCopy.put(propertyName, propsList);
1716                     } else {
1717                         propertyMapCopy.putAll(propertyValObj);
1718                     }
1719                 }
1720             }
1721         }
1722         propertyMapCopy.entrySet().forEach(entry -> addCalculatedConstraintsIntoPropertiesList(propertiesCopy, entry));
1723     }
1724
1725     private void addPropertyConstraintValueToList(String propertyName, Map<String, List<Object>> propertyValObj, List<Object> propsList) {
1726         if (propertyValObj.containsKey(propertyName)) {
1727             propsList.add(propertyValObj.get(propertyName));
1728         } else {
1729             propsList.add(propertyValObj);
1730         }
1731     }
1732
1733     private void addCalculatedConstraintsIntoPropertiesList(List<Map<String, List<Object>>> propertiesCopy, Entry<String, List<Object>> entry) {
1734         Map<String, List<Object>> tempMap = new HashMap<>();
1735         tempMap.put(entry.getKey(), entry.getValue());
1736         propertiesCopy.add(tempMap);
1737     }
1738
1739     private Map<String, String[]> buildSubstitutionMappingPropertyMapping(final Component component) {
1740         if (component == null || CollectionUtils.isEmpty(component.getInputs())) {
1741             return Collections.emptyMap();
1742         }
1743         return component.getInputs().stream().filter(InputDefinition::isMappedToComponentProperty).map(PropertyDataDefinition::getName)
1744             .collect(Collectors.toMap(inputName -> inputName, inputName -> new String[]{inputName}, (inputName1, inputName2) -> inputName1));
1745     }
1746
1747     private Map<String, String[]> buildSubstitutionMappingAttributesMapping(final Component component) {
1748         if (component == null || CollectionUtils.isEmpty(component.getOutputs())) {
1749             return Collections.emptyMap();
1750         }
1751         return component.getOutputs().stream().map(AttributeDataDefinition::getName)
1752             .collect(Collectors.toMap(outputName -> outputName, outputName -> new String[]{outputName}, (outputName1, outputName2) -> outputName1));
1753     }
1754
1755     private Optional<Map<String, ToscaProperty>> getProxyNodeTypeProperties(Component proxyComponent, Map<String, DataTypeDefinition> dataTypes) {
1756         if (Objects.isNull(proxyComponent)) {
1757             return Optional.empty();
1758         }
1759         final var proxyProperties = convertInputsToProperties(dataTypes, proxyComponent.getInputs(), proxyComponent.getUniqueId());
1760         if (CollectionUtils.isNotEmpty(proxyComponent.getProperties())) {
1761             proxyProperties.putAll(proxyComponent.getProperties().stream()
1762                 .map(propertyDefinition -> resolvePropertyValueFromInput(propertyDefinition, proxyComponent.getInputs())).collect(Collectors
1763                     .toMap(PropertyDataDefinition::getName,
1764                         property -> propertyConvertor.convertProperty(dataTypes, property, PropertyType.PROPERTY))));
1765         }
1766         return MapUtils.isNotEmpty(proxyProperties) ? Optional.of(proxyProperties) : Optional.empty();
1767     }
1768
1769     private Map<String, ToscaProperty> convertInputsToProperties(Map<String, DataTypeDefinition> dataTypes, List<InputDefinition> componentInputs,
1770                                                                  String componentUniqueId) {
1771         if (CollectionUtils.isEmpty(componentInputs)) {
1772             return new HashMap<>();
1773         }
1774         return componentInputs.stream().filter(input -> componentUniqueId.equals(input.getInstanceUniqueId()))
1775             .collect(Collectors.toMap(InputDefinition::getName, i -> propertyConvertor.convertProperty(dataTypes, i, PropertyType.INPUT)));
1776     }
1777
1778     private Optional<Map<String, Object>> getProxyNodeTypeInterfaces(Component proxyComponent, Map<String, DataTypeDefinition> dataTypes) {
1779         if (Objects.isNull(proxyComponent) || MapUtils.isEmpty(proxyComponent.getInterfaces())) {
1780             return Optional.empty();
1781         }
1782         Map<String, InterfaceDefinition> proxyComponentInterfaces = proxyComponent.getInterfaces();
1783         //Unset artifact path for operation implementation for proxy node types as for operations with artifacts it is
1784
1785         // always available in the proxy node template
1786         removeOperationImplementationForProxyNodeType(proxyComponentInterfaces);
1787         return Optional
1788             .ofNullable(interfacesOperationsConverter.getInterfacesMap(proxyComponent, null, proxyComponentInterfaces, dataTypes, false, false));
1789     }
1790
1791     private Configuration getConfiguration() {
1792         return ConfigurationManager.getConfigurationManager().getConfiguration();
1793     }
1794
1795     private static class CustomRepresenter extends Representer {
1796
1797         CustomRepresenter() {
1798             super();
1799             this.representers.put(ToscaPropertyAssignment.class, new RepresentToscaPropertyAssignment());
1800             this.representers.put(ToscaAttribute.class, new RepresentToscaAttribute());
1801             // null representer is exceptional and it is stored as an instance
1802
1803             // variable.
1804             this.nullRepresenter = new RepresentNull();
1805         }
1806
1807         public boolean validateGetInputValue(final Object valueObj) {
1808             if (!(valueObj instanceof List) && !(valueObj instanceof String)) {
1809                 return false;
1810             }
1811             if (valueObj instanceof List) {
1812                 return ((List) valueObj).size() > 1;
1813             }
1814             return true;
1815         }
1816
1817         public boolean validateGetPropertyOrAttributeValue(final Object valueObj) {
1818             if (valueObj instanceof List) {
1819                 return ((List) valueObj).size() > 1;
1820             }
1821             return false;
1822         }
1823
1824         @Override
1825         protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {
1826             if (propertyValue == null) {
1827                 return null;
1828             }
1829             // skip not relevant for Tosca property
1830             if ("dependencies".equals(property.getName())) {
1831                 return null;
1832             }
1833             if (javaBean instanceof ToscaRelationshipTemplate && "name".equals(property.getName())) {
1834                 return null;
1835             }
1836             removeDefaultP(propertyValue);
1837             NodeTuple defaultNode = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
1838             if (javaBean instanceof ToscaTopolgyTemplate && "relationshipTemplates".equals(property.getName())) {
1839                 return new NodeTuple(representData("relationship_templates"), defaultNode.getValueNode());
1840             }
1841             return "_defaultp_".equals(property.getName()) ? new NodeTuple(representData("default"), defaultNode.getValueNode()) : defaultNode;
1842         }
1843
1844         private void removeDefaultP(final Object propertyValue) {
1845             if (propertyValue instanceof Map) {
1846                 final Map mapPropertyValue = ((Map) propertyValue);
1847                 final Iterator<Entry> iter = mapPropertyValue.entrySet().iterator();
1848                 Object defaultValue = null;
1849                 while (iter.hasNext()) {
1850                     final Map.Entry entry = iter.next();
1851                     if ("_defaultp_".equals(entry.getKey())) {
1852                         defaultValue = entry.getValue();
1853                         iter.remove();
1854                     } else if (entry.getValue() instanceof Map) {
1855                         removeDefaultP(entry.getValue());
1856                     }
1857                 }
1858                 if (defaultValue != null) {
1859                     mapPropertyValue.putIfAbsent("default", defaultValue);
1860                 }
1861             }
1862         }
1863
1864         @Override
1865         protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
1866             // remove the bean type from the output yaml (!! ...)
1867             if (!classTags.containsKey(javaBean.getClass())) {
1868                 addClassTag(javaBean.getClass(), Tag.MAP);
1869             }
1870             return super.representJavaBean(properties, javaBean);
1871         }
1872
1873         private class RepresentToscaAttribute implements Represent {
1874
1875             @Override
1876             public Node representData(Object data) {
1877                 final ToscaAttribute toscaAttribute = (ToscaAttribute) data;
1878                 return represent(toscaAttribute.asToscaMap());
1879             }
1880         }
1881
1882         private class RepresentToscaPropertyAssignment implements Represent {
1883
1884             public Node representData(Object data) {
1885                 final ToscaPropertyAssignment toscaOperationAssignment = (ToscaPropertyAssignment) data;
1886                 if (toscaOperationAssignment.getValue() instanceof String) {
1887                     final String stringValue = (String) toscaOperationAssignment.getValue();
1888                     if (isPropertyOrAttributeFunction(stringValue)) {
1889                         return representGetAttribute(stringValue);
1890                     }
1891                     return representScalar(Tag.STR, stringValue);
1892                 }
1893                 return represent(null);
1894             }
1895
1896             public Node representGetAttribute(final String getAttributeFunction) {
1897                 return represent(new Yaml().load(getAttributeFunction));
1898             }
1899
1900             public boolean isPropertyOrAttributeFunction(final String value) {
1901                 try {
1902                     final Yaml yaml = new Yaml();
1903                     final Object yamlObj = yaml.load(value);
1904                     if (!(yamlObj instanceof Map)) {
1905                         return false;
1906                     }
1907                     final Map<String, Object> getAttributeMap = (Map) yamlObj;
1908                     if (getAttributeMap.size() != 1) {
1909                         return false;
1910                     }
1911                     final List<String> functionList = Arrays
1912                         .asList(GET_ATTRIBUTE.getFunctionName(), GET_INPUT.getFunctionName(), GET_PROPERTY.getFunctionName());
1913                     final Optional<String> function = getAttributeMap.keySet().stream()
1914                         .filter(key -> functionList.stream().anyMatch(function1 -> function1.equals(key))).findFirst();
1915                     if (function.isEmpty()) {
1916                         return false;
1917                     }
1918                     final String functionName = function.get();
1919                     final Object getAttributeValueObj = getAttributeMap.get(functionName);
1920                     if (GET_INPUT.getFunctionName().equals(functionName)) {
1921                         return validateGetInputValue(getAttributeValueObj);
1922                     } else {
1923                         return validateGetPropertyOrAttributeValue(getAttributeValueObj);
1924                     }
1925                 } catch (final Exception ignored) {
1926                     return false;
1927                 }
1928             }
1929         }
1930
1931         private class RepresentNull implements Represent {
1932
1933             @Override
1934             public Node representData(Object data) {
1935                 // possible values are here http://yaml.org/type/null.html
1936                 return representScalar(Tag.NULL, "");
1937             }
1938         }
1939     }
1940
1941     private static class UnsortedPropertyUtils extends PropertyUtils {
1942
1943         @Override
1944         protected Set<Property> createPropertySet(Class type, BeanAccess bAccess) {
1945             Collection<Property> fields = getPropertiesMap(type, BeanAccess.FIELD).values();
1946             return new LinkedHashSet<>(fields);
1947         }
1948     }
1949
1950 }