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