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