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