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