fix capabilities
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / tosca / CapabiltyRequirementConvertor.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
21 package org.openecomp.sdc.be.tosca;
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import java.util.stream.Collectors;
31
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.collections.MapUtils;
34 import org.apache.commons.lang3.tuple.ImmutablePair;
35 import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
36 import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
37 import org.openecomp.sdc.be.model.CapabilityDefinition;
38 import org.openecomp.sdc.be.model.Component;
39 import org.openecomp.sdc.be.model.ComponentInstance;
40 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
41 import org.openecomp.sdc.be.model.ComponentParametersView;
42 import org.openecomp.sdc.be.model.DataTypeDefinition;
43 import org.openecomp.sdc.be.model.PropertyDefinition;
44 import org.openecomp.sdc.be.model.RequirementDefinition;
45 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
46 import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter;
47 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
48 import org.openecomp.sdc.be.tosca.ToscaUtils.SubstituitionEntry;
49 import org.openecomp.sdc.be.tosca.model.SubstitutionMapping;
50 import org.openecomp.sdc.be.tosca.model.ToscaCapability;
51 import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
52 import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
53 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
54 import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
55 import org.openecomp.sdc.be.tosca.model.ToscaTemplateCapability;
56 import org.openecomp.sdc.common.util.ValidationUtils;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.beans.factory.annotation.Autowired;
60 import org.springframework.context.annotation.Scope;
61
62 import com.google.common.collect.Iterables;
63 import com.google.common.collect.Lists;
64 import com.google.common.collect.Maps;
65
66 import fj.data.Either;
67 /**
68  * Allows to convert requirements\capabilities of a component to requirements\capabilities of a substitution mappings section of a tosca template
69  *
70  */
71 @org.springframework.stereotype.Component("capabilty-requirement-convertor")
72 @Scope(value = "singleton")
73 public class CapabiltyRequirementConvertor {
74         
75         private static final String NO_CAPABILITIES = "No Capabilities for node type";
76         private static CapabiltyRequirementConvertor instance;
77         private static Logger logger = LoggerFactory.getLogger(CapabiltyRequirementConvertor.class.getName());
78         public static final String PATH_DELIMITER = ".";
79         
80         @Autowired
81         private ToscaOperationFacade toscaOperationFacade;
82         
83         protected CapabiltyRequirementConvertor() {
84
85         }
86
87         public static synchronized CapabiltyRequirementConvertor getInstance() {
88                 if (instance == null) {
89                         instance = new CapabiltyRequirementConvertor();
90                 }
91                 return instance;
92         }
93         /**
94          * Allows to convert capabilities of a component to capabilities of a substitution mappings section of a tosca template
95          * @param componentInstance
96          * @param dataTypes
97          * @param nodeTemplate
98          * @return
99          */
100         public Either<ToscaNodeTemplate, ToscaError> convertComponentInstanceCapabilties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate) {
101
102                 Map<String, List<CapabilityDefinition>> capabilitiesInst = componentInstance.getCapabilities();
103                 if (capabilitiesInst != null && !capabilitiesInst.isEmpty()) {
104                         Map<String, ToscaTemplateCapability> capabilties = new HashMap<>();
105                         capabilitiesInst.entrySet().forEach(e -> {
106                                 List<CapabilityDefinition> capList = e.getValue();
107                                 if (capList != null && !capList.isEmpty()) {
108                                         capList.forEach(c -> convertOverridenProperties(componentInstance, dataTypes, capabilties, c));
109                                 }
110                         });
111                         if (MapUtils.isNotEmpty(capabilties)) {
112                                 nodeTemplate.setCapabilities(capabilties);
113                         }
114                 }
115                 return Either.left(nodeTemplate);
116         }
117
118         private void convertOverridenProperties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, Map<String, ToscaTemplateCapability> capabilties, CapabilityDefinition c) {
119                 List<ComponentInstanceProperty> properties = c.getProperties();
120                 if (properties != null && !properties.isEmpty()) {
121                         properties
122                         .stream()
123                         .filter(p -> p.getValue() != null || p.getDefaultValue() != null)
124                         .forEach(p -> convertOverridenProperty(componentInstance, dataTypes, capabilties, c, p));
125                 }
126         }
127
128         private void convertOverridenProperty(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, Map<String, ToscaTemplateCapability> capabilties, CapabilityDefinition c, ComponentInstanceProperty p) {
129                 if (logger.isDebugEnabled()) {
130                         logger.debug("Exist overriden property {} for capabity {} with value {}", p.getName(), c.getName(), p.getValue());
131                 }
132                 ToscaTemplateCapability toscaTemplateCapability = capabilties.get(c.getName());
133                 if (toscaTemplateCapability == null) {
134                         toscaTemplateCapability = new ToscaTemplateCapability();
135                         capabilties.put(c.getName(), toscaTemplateCapability);
136                 }
137                 Map<String, Object> toscaCapProp = toscaTemplateCapability.getProperties();
138                 if (toscaCapProp == null) {
139                         toscaCapProp = new HashMap<>();
140                 }
141                 Object convertedValue = convertInstanceProperty(dataTypes, componentInstance, p);
142                 toscaCapProp.put(p.getName(), convertedValue);
143                 toscaTemplateCapability.setProperties(toscaCapProp);
144         }
145
146         private Object convertInstanceProperty(Map<String, DataTypeDefinition> dataTypes, ComponentInstance componentInstance, ComponentInstanceProperty prop) {
147                 logger.debug("Convert property {} for instance {}", prop.getName(), componentInstance.getUniqueId());
148                 String propertyType = prop.getType();
149                 String innerType = null;
150                 if (prop.getSchema() != null && prop.getSchema().getProperty() != null) {
151                         innerType = prop.getSchema().getProperty().getType();
152                 }
153                 String propValue = prop.getValue() == null ? prop.getDefaultValue() : prop.getValue();
154                 return PropertyConvertor.getInstance().convertToToscaObject(propertyType, propValue, innerType, dataTypes);
155         }
156         /**
157          * Allows to convert requirements of a node type to tosca template requirements representation
158          * @param component
159          * @param nodeType
160          * @return
161          */
162         public Either<ToscaNodeType, ToscaError> convertRequirements(Component component, ToscaNodeType nodeType) {
163                 List<Map<String, ToscaRequirement>> toscaRequirements = convertRequirementsAsList(component);
164                 if (!toscaRequirements.isEmpty()) {
165                         nodeType.setRequirements(toscaRequirements);
166                 }
167                 logger.debug("Finish convert Requirements for node type");
168
169                 return Either.left(nodeType);
170         }
171
172         /**
173          * Allows to convert component requirements to the tosca template substitution mappings requirements
174          * @param componentsCache
175          * @param component
176          * @param substitutionMappings
177          * @return
178          */
179         public Either<SubstitutionMapping, ToscaError> convertSubstitutionMappingRequirements(Map<String,Component> componentsCache, Component component, SubstitutionMapping substitutionMappings) {
180                 Either<SubstitutionMapping, ToscaError> result = Either.left(substitutionMappings);
181                 Either<Map<String, String[]>, ToscaError> toscaRequirementsRes = convertSubstitutionMappingRequirementsAsMap(componentsCache, component);
182                 if(toscaRequirementsRes.isRight()){
183                         result = Either.right(toscaRequirementsRes.right().value());
184                         logger.error("Failed convert requirements for the component {}. ", component.getName());
185                 } else if (MapUtils.isNotEmpty(toscaRequirementsRes.left().value())) {
186                         substitutionMappings.setRequirements(toscaRequirementsRes.left().value());
187                         result = Either.left(substitutionMappings);
188                         logger.debug("Finish convert requirements for the component {}. ", component.getName());
189                 }
190                 return result;
191         }
192
193         private List<Map<String, ToscaRequirement>> convertRequirementsAsList(Component component) {
194                 Map<String, List<RequirementDefinition>> requirements = component.getRequirements();
195                 List<Map<String, ToscaRequirement>> toscaRequirements = new ArrayList<>();
196                 if (requirements != null) {
197                         for (Map.Entry<String, List<RequirementDefinition>> entry : requirements.entrySet()) {
198                                 entry.getValue().stream().filter(r -> filter(component, r.getOwnerId())).forEach(r -> {
199                                         ImmutablePair<String, ToscaRequirement> pair = convertRequirement(component, ModelConverter.isAtomicComponent(component), r);
200                                         Map<String, ToscaRequirement> requirement = new HashMap<>();
201
202                                         requirement.put(pair.left, pair.right);
203                                         toscaRequirements.add(requirement);
204                                 });
205                                 logger.debug("Finish convert Requirements for node type");
206                         }
207                 } else {
208                         logger.debug("No Requirements for node type");
209                 }
210                 return toscaRequirements;
211         }
212
213         private boolean filter(Component component, String ownerId) {
214                 return !ModelConverter.isAtomicComponent(component) || isNodeTypeOwner(component, ownerId) || (ModelConverter.isAtomicComponent(component) && ownerId == null);
215         }
216
217         private boolean isNodeTypeOwner(Component component, String ownerId) {
218                 return ModelConverter.isAtomicComponent(component) && component.getUniqueId().equals(ownerId);
219         }
220         
221         private String getSubPathByLastDelimiterAppearance(String path) {
222                 return path.substring(path.lastIndexOf(PATH_DELIMITER) + 1);
223         }
224
225         private Either<Map<String, String[]>, ToscaError> convertSubstitutionMappingRequirementsAsMap(Map<String, Component> componentsCache, Component component) {
226                 Map<String, List<RequirementDefinition>> requirements = component.getRequirements();
227                 Either<Map<String, String[]>, ToscaError> result;
228                 if (requirements != null) {
229                         result = buildAddSubstitutionMappingsRequirements(componentsCache, component, requirements);
230                 } else {
231                         result = Either.left(Maps.newHashMap());
232                         logger.debug("No requirements for substitution mappings section of a tosca template of the component {}. ", component.getName());
233                 }
234                 return result;
235         }
236
237         private Either<Map<String, String[]>, ToscaError> buildAddSubstitutionMappingsRequirements(Map<String, Component> componentsCache, Component component, Map<String, List<RequirementDefinition>> requirements) {
238                 
239                 Map<String, String[]> toscaRequirements = new HashMap<>();
240                 Either<Map<String, String[]>, ToscaError> result = null;
241                 for (Map.Entry<String, List<RequirementDefinition>> entry : requirements.entrySet()) {
242                         Optional<RequirementDefinition> failedToAddRequirement = entry.getValue()
243                                         .stream()
244                                         .filter(r->!addEntry(componentsCache, toscaRequirements, component, r.getName(), r.getParentName(), r.getPath()))
245                                         .findAny();
246                         if(failedToAddRequirement.isPresent()){
247                                 logger.error("Failed to convert requirement {} for substitution mappings section of a tosca template of the component {}. ",
248                                                 failedToAddRequirement.get().getName(), component.getName());
249                                 result = Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR);
250                         }
251                         logger.debug("Finish convert requirements for the component {}. ", component.getName());
252                 }
253                 if(result == null){
254                         result = Either.left(toscaRequirements);
255                 }
256                 return result;
257         }
258         
259         private Either<Map<String, String[]>, ToscaError> buildAddSubstitutionMappingsCapabilities(Map<String, Component> componentsCache, Component component, Map<String, List<CapabilityDefinition>> capabilities) {
260                 
261                 Map<String, String[]> toscaRequirements = new HashMap<>();
262                 Either<Map<String, String[]>, ToscaError> result = null;
263                 for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
264                         Optional<CapabilityDefinition> failedToAddRequirement = entry.getValue()
265                                         .stream()
266                                         .filter(c->!addEntry(componentsCache, toscaRequirements, component, c.getName(), c.getParentName(), c.getPath()))
267                                         .findAny();
268                         if(failedToAddRequirement.isPresent()){
269                                 logger.error("Failed to convert capalility {} for substitution mappings section of a tosca template of the component {}. ",
270                                                 failedToAddRequirement.get().getName(), component.getName());
271                                 result = Either.right(ToscaError.NODE_TYPE_CAPABILITY_ERROR);
272                         }
273                         logger.debug("Finish convert capalilities for the component {}. ", component.getName());
274                 }
275                 if(result == null){
276                         result = Either.left(toscaRequirements);
277                 }
278                 return result;
279         }
280         
281         private boolean addEntry(Map<String,Component> componentsCache, Map<String, String[]> capReqMap, Component component, String name, String parentName, List<String> path){
282
283                 SubstituitionEntry entry = new SubstituitionEntry(name, parentName, "");
284                 
285                 if(shouldBuildSubstitutionName(component, path) && !buildSubstitutedNamePerInstance(componentsCache, component, name, path, entry)){
286                         return false;
287                 }
288                 logger.debug("The requirement/capability {} belongs to the component {} ", entry.getFullName(), component.getUniqueId());
289                 if (entry.getSourceName() != null) {
290                         addEntry(capReqMap, component, path, entry);
291                 }
292                 logger.debug("Finish convert the requirement/capability {} for the component {}. ", entry.getFullName(), component.getName());
293                 return true;
294         
295         }
296
297         private boolean shouldBuildSubstitutionName(Component component, List<String> path) {
298                 return !ToscaUtils.isComplexVfc(component) && CollectionUtils.isNotEmpty(path) && path.iterator().hasNext();
299         }
300
301         private boolean buildSubstitutedNamePerInstance(Map<String, Component> componentsCache, Component component, String name, List<String> path, SubstituitionEntry entry) {
302                 Optional<ComponentInstance> ci = component.getComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst();
303                 if(ci.isPresent()){
304                         Either<String, Boolean> buildSubstitutedName = buildSubstitutedName(componentsCache, name, path, ci.get());
305                         if(buildSubstitutedName.isRight()){
306                                 return false;
307                         }
308                         entry.setFullName(ci.get().getNormalizedName() + '.' + buildSubstitutedName.left().value());
309                         entry.setSourceName(buildSubstitutedName.left().value());
310                 } else {
311                         return false;
312                 }
313                 return true;
314         }
315
316         private void addEntry(Map<String, String[]> toscaRequirements, Component component, List<String> capPath, SubstituitionEntry entry) {
317                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(Iterables.getLast(capPath))).findFirst();
318                 if (findFirst.isPresent()) {
319                         entry.setOwner(findFirst.get().getNormalizedName());
320                 }
321                 toscaRequirements.put(entry.getFullName(), new String[] { entry.getOwner(), entry.getSourceName() });
322         }
323
324         private Either<String, Boolean> buildSubstitutedName(Map<String, Component> componentsCache, String name, List<String> path, ComponentInstance instance) {
325                 
326                 Either<String, Boolean> result = null;
327                 Either<Component, Boolean> getOriginRes = getOriginComponent(componentsCache, instance);
328                 if(getOriginRes.isRight()){
329                         logger.debug("Failed to build substituted name for the capability/requirement {}. Failed to get an origin component with uniqueId {}", name, instance.getComponentUid());
330                         result = Either.right(false);
331                 }
332                 if(result == null){
333                         result = buildSubstitutedName(componentsCache, getOriginRes.left().value(), Lists.newArrayList(path.subList(0, path.size()-1)), name);
334                 }
335                 return result;
336         }
337
338         private String getRequirementPath(Component component, RequirementDefinition r) {
339                         
340                 // Evg : for the last in path take real instance name and not "decrypt" unique id. ( instance name can be change and not equal to id..)
341                 // dirty quick fix. must be changed as capability redesign
342                 List<String> capPath = r.getPath();
343                 String lastInPath = capPath.get(capPath.size() - 1);
344                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(lastInPath)).findFirst();
345                 if (findFirst.isPresent()) {
346                         String lastInPathName = findFirst.get().getNormalizedName();
347
348                         if (capPath.size() > 1) {
349                                 List<String> pathArray = Lists.reverse(capPath.stream().map(path -> ValidationUtils.normalizeComponentInstanceName(getSubPathByLastDelimiterAppearance(path))).collect(Collectors.toList()));
350
351                                 return new StringBuilder().append(lastInPathName).append(PATH_DELIMITER).append(String.join(PATH_DELIMITER, pathArray.subList(1, pathArray.size() ))).append(PATH_DELIMITER).append(r.getName()).toString();
352                         }else{
353                                 return new StringBuilder().append(lastInPathName).append(PATH_DELIMITER).append(r.getName()).toString();
354                         }
355                 }
356                 return "";
357         }
358
359         private ImmutablePair<String, ToscaRequirement> convertRequirement(Component component, boolean isNodeType, RequirementDefinition r) {
360                 String name = r.getName();
361                 if (!isNodeType) {
362                         name = getRequirementPath(component, r);
363                 }
364                 logger.debug("the requirement {} belongs to resource {} ", name, component.getUniqueId());
365                 ToscaRequirement toscaRequirement = new ToscaRequirement();
366
367                 List<Object> occurences = new ArrayList<>();
368                 occurences.add(Integer.valueOf(r.getMinOccurrences()));
369                 if (r.getMaxOccurrences().equals(RequirementDataDefinition.MAX_OCCURRENCES)) {
370                         occurences.add(r.getMaxOccurrences());
371                 } else {
372                         occurences.add(Integer.valueOf(r.getMaxOccurrences()));
373                 }
374                 toscaRequirement.setOccurrences(occurences);
375                 toscaRequirement.setNode(r.getNode());
376                 toscaRequirement.setCapability(r.getCapability());
377                 toscaRequirement.setRelationship(r.getRelationship());
378
379                 return new ImmutablePair<>(name, toscaRequirement);
380         }
381
382         /**
383          * Allows to convert capabilities of a node type to tosca template capabilities
384          * @param component
385          * @param dataTypes
386          * @return
387          */
388         public Map<String, ToscaCapability> convertCapabilities(Component component, Map<String, DataTypeDefinition> dataTypes) {
389                 Map<String, List<CapabilityDefinition>> capabilities = component.getCapabilities();
390                 Map<String, ToscaCapability> toscaCapabilities = new HashMap<>();
391                 if (capabilities != null) {
392                         boolean isNodeType = ModelConverter.isAtomicComponent(component);
393                         for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
394                                 entry.getValue().stream().filter(c -> filter(component, c.getOwnerId())).forEach(c -> convertCapabilty(component, toscaCapabilities, isNodeType, c, dataTypes));
395                         }
396                 } else {
397                         logger.debug(NO_CAPABILITIES);
398                 }
399
400                 return toscaCapabilities;
401         }
402
403         /**
404          * Allows to convert capabilities of a server proxy node type to tosca template capabilities
405          * @param component
406          * @param proxyComponent
407          * @param instanceProxy
408          * @param dataTypes
409          * @return
410          */
411         public Map<String, ToscaCapability> convertProxyCapabilities(Component component, Component proxyComponent, ComponentInstance instanceProxy, Map<String, DataTypeDefinition> dataTypes) {
412                 Map<String, List<CapabilityDefinition>> capabilities = instanceProxy.getCapabilities();
413                 Map<String, ToscaCapability> toscaCapabilities = new HashMap<>();
414                 if (capabilities != null) {
415                         boolean isNodeType = ModelConverter.isAtomicComponent(component);
416                         for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
417                                 entry.getValue().stream().forEach(c -> convertCapabilty(proxyComponent, toscaCapabilities, isNodeType, c, dataTypes));
418                         }
419                 } else {
420                         logger.debug(NO_CAPABILITIES);
421                 }
422
423                 return toscaCapabilities;
424         }
425
426         /**
427          * Allows to convert component capabilities to the tosca template substitution mappings capabilities
428          * @param componentsCache
429          * @param component
430          * @return
431          */
432         public Either<Map<String, String[]>, ToscaError> convertSubstitutionMappingCapabilities(Map<String, Component> componentsCache, Component component) {
433                 Map<String, List<CapabilityDefinition>> capabilities = component.getCapabilities();
434                 Either<Map<String, String[]>, ToscaError> res  = null;
435                 if (capabilities != null) {
436                         res = buildAddSubstitutionMappingsCapabilities(componentsCache, component, capabilities);
437                 } else {
438                         logger.debug(NO_CAPABILITIES);
439                         res = Either.left(new HashMap<>());
440                 }
441                 return res;
442         }
443         
444         private String getCapabilityPath(CapabilityDefinition c, Component component) {
445                 // Evg : for the last in path take real instance name and not "decrypt" unique id. ( instance name can be change and not equal to id..)
446                 // dirty quick fix. must be changed as capability redesign
447                 List<String> capPath = c.getPath();
448                 String lastInPath = capPath.get(capPath.size() - 1);
449                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(lastInPath)).findFirst();
450                 if (findFirst.isPresent()) {
451                         String lastInPathName = findFirst.get().getNormalizedName();
452
453                         if (capPath.size() > 1) {
454                                 List<String> pathArray = Lists.reverse(capPath.stream().map(path -> ValidationUtils.normalizeComponentInstanceName(getSubPathByLastDelimiterAppearance(path))).collect(Collectors.toList()));
455
456                                 return new StringBuilder().append(lastInPathName).append(PATH_DELIMITER).append(String.join(PATH_DELIMITER, pathArray.subList(1, pathArray.size() ))).append(PATH_DELIMITER).append(c.getName()).toString();
457                         }else{
458                                 return new StringBuilder().append(lastInPathName).append(PATH_DELIMITER).append(c.getName()).toString();
459                         }
460                 }
461                 return "";
462         }
463
464         private void convertCapabilty(Component component, Map<String, ToscaCapability> toscaCapabilities, boolean isNodeType, CapabilityDefinition c, Map<String, DataTypeDefinition> dataTypes) {
465                 String name = c.getName();
466                 if (!isNodeType) {
467                         name = getCapabilityPath(c, component);
468                 }
469                 logger.debug("the capabilty {} belongs to resource {} ", name, component.getUniqueId());
470                 ToscaCapability toscaCapability = new ToscaCapability();
471                 toscaCapability.setDescription(c.getDescription());
472                 toscaCapability.setType(c.getType());
473
474                 List<Object> occurences = new ArrayList<>();
475                 occurences.add(Integer.valueOf(c.getMinOccurrences()));
476                 if (c.getMaxOccurrences().equals(CapabilityDataDefinition.MAX_OCCURRENCES)) {
477                         occurences.add(c.getMaxOccurrences());
478                 } else {
479                         occurences.add(Integer.valueOf(c.getMaxOccurrences()));
480                 }
481                 toscaCapability.setOccurrences(occurences);
482
483                 toscaCapability.setValid_source_types(c.getValidSourceTypes());
484                 List<ComponentInstanceProperty> properties = c.getProperties();
485                 if (properties != null && !properties.isEmpty()) {
486                         Map<String, ToscaProperty> toscaProperties = new HashMap<>();
487                         for (PropertyDefinition property : properties) {
488                                 ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, true);
489                                 toscaProperties.put(property.getName(), toscaProperty);
490                         }
491                         toscaCapability.setProperties(toscaProperties);
492                 }
493                 toscaCapabilities.put(name, toscaCapability);
494         }
495         
496         Either<String, Boolean> buildSubstitutedName(Map<String, Component> originComponents, Component originComponent, List<String> path, String name) {
497                 StringBuilder substitutedName = new StringBuilder();
498                 boolean nameBuiltSuccessfully = true;
499                 Either<String, Boolean> result;
500                 if(CollectionUtils.isNotEmpty(path) && !ToscaUtils.isComplexVfc(originComponent)){
501                         Collections.reverse(path);
502                         Iterator<String> instanceIdIter = path.iterator();
503                         nameBuiltSuccessfully = appendNameRecursively(originComponents, originComponent, instanceIdIter, substitutedName);
504                 }
505                 if(nameBuiltSuccessfully){
506                         result = Either.left(substitutedName.append(name).toString());
507                 } else {
508                         result = Either.right(nameBuiltSuccessfully);
509                 }
510                 return result;
511         }
512
513         private boolean appendNameRecursively(Map<String, Component> originComponents, Component originComponent, Iterator<String> instanceIdIter, StringBuilder substitutedName) {
514                 if(CollectionUtils.isNotEmpty(originComponent.getComponentInstances()) && instanceIdIter.hasNext()){
515                         String instanceId = instanceIdIter.next();
516                         Optional<ComponentInstance> instanceOpt = originComponent.getComponentInstances().stream().filter(i -> i.getUniqueId().equals(instanceId)).findFirst();
517                         if(!instanceOpt.isPresent()){
518                                 logger.debug("Failed to find an instance with uniqueId {} on a component with uniqueId {}", instanceId, originComponent.getUniqueId());
519                                 return false;
520                         }
521                         Either<Component, Boolean> getOriginRes = getOriginComponent(originComponents, instanceOpt.get());
522                         if(getOriginRes.isRight()){
523                                 return false;
524                         }
525                         appendNameRecursively(originComponents, getOriginRes.left().value(), instanceIdIter, substitutedName);
526                         substitutedName.append(instanceOpt.get().getNormalizedName()).append('.');
527                         return true;
528                 }
529                 return true;
530         }
531
532         private Either<Component, Boolean> getOriginComponent(Map<String, Component> originComponents, ComponentInstance instance) {
533                 Either<Component, Boolean> result;
534                 Either<Component, StorageOperationStatus> getOriginRes;
535                 if(originComponents.containsKey(instance.getComponentUid())){
536                         result = Either.left(originComponents.get(instance.getComponentUid()));
537                 } else {
538                         ComponentParametersView filter = new ComponentParametersView(true);
539                         filter.setIgnoreComponentInstances(false);
540                         getOriginRes = toscaOperationFacade.getToscaElement(instance.getComponentUid(), filter);
541                         if(getOriginRes.isRight()){
542                                 logger.debug("Failed to get an origin component with uniqueId {}", instance.getComponentUid());
543                                 result = Either.right(false);
544                         } else {
545                                 result = Either.left(getOriginRes.left().value());
546                                 originComponents.put(getOriginRes.left().value().getUniqueId(), getOriginRes.left().value());
547                         }
548                 }
549                 return result;
550         }
551
552 }