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