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