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