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