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