Nodes in service template fix
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / tosca / CapabiltyRequirementConvertor.java
1 /*-
2
3  * ============LICENSE_START=======================================================
4  * SDC
5  * ================================================================================
6  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.sdc.be.tosca;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import java.util.stream.Collectors;
30
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
33 import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
34 import org.openecomp.sdc.be.model.CapabilityDefinition;
35 import org.openecomp.sdc.be.model.Component;
36 import org.openecomp.sdc.be.model.ComponentInstance;
37 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
38 import org.openecomp.sdc.be.model.DataTypeDefinition;
39 import org.openecomp.sdc.be.model.PropertyDefinition;
40 import org.openecomp.sdc.be.model.RequirementDefinition;
41 import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter;
42 import org.openecomp.sdc.be.tosca.model.SubstitutionMapping;
43 import org.openecomp.sdc.be.tosca.model.ToscaCapability;
44 import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
45 import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
46 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
47 import org.openecomp.sdc.be.tosca.model.ToscaRequirement;
48 import org.openecomp.sdc.be.tosca.model.ToscaTemplateCapability;
49 import org.openecomp.sdc.common.util.ValidationUtils;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.google.common.collect.Lists;
54
55 import fj.data.Either;
56
57 public class CapabiltyRequirementConvertor {
58         private static CapabiltyRequirementConvertor instance;
59         public final static String PATH_DELIMITER = ".";
60         
61         protected CapabiltyRequirementConvertor() {
62
63         }
64
65         public static synchronized CapabiltyRequirementConvertor getInstance() {
66                 if (instance == null) {
67                         instance = new CapabiltyRequirementConvertor();
68                 }
69                 return instance;
70         }
71
72         private static Logger log = LoggerFactory.getLogger(CapabiltyRequirementConvertor.class.getName());
73
74         public Either<ToscaNodeTemplate, ToscaError> convertComponentInstanceCapabilties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate) {
75
76                 Map<String, List<CapabilityDefinition>> capabilitiesInst = componentInstance.getCapabilities();
77                 if (capabilitiesInst != null && !capabilitiesInst.isEmpty()) {
78                         Map<String, ToscaTemplateCapability> capabilties = new HashMap<>();
79                         capabilitiesInst.entrySet().forEach(e -> {
80                                 List<CapabilityDefinition> capList = e.getValue();
81                                 if (capList != null && !capList.isEmpty()) {
82                                         capList.forEach(c -> {
83                                                 convertOverridenProperties(componentInstance, dataTypes, capabilties, c);
84                                         });
85                                 }
86                         });
87                         if (capabilties != null && !capabilties.isEmpty()) {
88                                 nodeTemplate.setCapabilities(capabilties);
89                         }
90                 }
91                 return Either.left(nodeTemplate);
92         }
93
94         private void convertOverridenProperties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, Map<String, ToscaTemplateCapability> capabilties, CapabilityDefinition c) {
95                 List<ComponentInstanceProperty> properties = c.getProperties();
96                 if (properties != null && !properties.isEmpty()) {
97                         properties.stream().filter(p -> (p.getValue() != null || p.getDefaultValue() != null)).forEach(p -> {
98                                 convertOverridenProperty(componentInstance, dataTypes, capabilties, c, p);
99                         });
100                 }
101         }
102
103         private void convertOverridenProperty(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, Map<String, ToscaTemplateCapability> capabilties, CapabilityDefinition c, ComponentInstanceProperty p) {
104                 if (log.isDebugEnabled()) {
105                         log.debug("Exist overriden property {} for capabity {} with value {}", p.getName(), c.getName(), p.getValue());
106                 }
107                 ToscaTemplateCapability toscaTemplateCapability = capabilties.get(c.getName());
108                 if (toscaTemplateCapability == null) {
109                         toscaTemplateCapability = new ToscaTemplateCapability();
110                         capabilties.put(c.getName(), toscaTemplateCapability);
111                 }
112                 Map<String, Object> toscaCapProp = toscaTemplateCapability.getProperties();
113                 if (toscaCapProp == null) {
114                         toscaCapProp = new HashMap<>();
115                 }
116                 Object convertedValue = convertInstanceProperty(dataTypes, componentInstance, p);
117                 toscaCapProp.put(p.getName(), convertedValue);
118                 toscaTemplateCapability.setProperties(toscaCapProp);
119         }
120
121         private Object convertInstanceProperty(Map<String, DataTypeDefinition> dataTypes, ComponentInstance componentInstance, ComponentInstanceProperty prop) {
122                 log.debug("Convert property {} for instance {}", prop.getName(), componentInstance.getUniqueId());
123                 String propertyType = prop.getType();
124                 String innerType = null;
125                 if (prop.getSchema() != null && prop.getSchema().getProperty() != null) {
126                         innerType = prop.getSchema().getProperty().getType();
127                 }
128                 String propValue = prop.getValue() == null ? prop.getDefaultValue() : prop.getValue();
129                 Object convertedValue = PropertyConvertor.getInstance().convertToToscaObject(propertyType, propValue, innerType, dataTypes);
130                 return convertedValue;
131         }
132
133         public Either<ToscaNodeType, ToscaError> convertRequirements(Component component, ToscaNodeType nodeType) {
134                 List<Map<String, ToscaRequirement>> toscaRequirements = convertRequirementsAsList(component);
135                 if (!toscaRequirements.isEmpty()) {
136                         nodeType.setRequirements(toscaRequirements);
137                 }
138                 log.debug("Finish convert Requirements for node type");
139
140                 return Either.left(nodeType);
141         }
142
143         public Either<SubstitutionMapping, ToscaError> convertSubstitutionMappingRequirements(Component component, SubstitutionMapping substitutionMapping) {
144                 Map<String, String[]> toscaRequirements = convertSubstitutionMappingRequirementsAsMap(component);
145                 if (!toscaRequirements.isEmpty()) {
146                         substitutionMapping.setRequirements(toscaRequirements);
147                 }
148                 log.debug("Finish convert Requirements for node type");
149
150                 return Either.left(substitutionMapping);
151         }
152
153         private List<Map<String, ToscaRequirement>> convertRequirementsAsList(Component component) {
154                 Map<String, List<RequirementDefinition>> requirements = component.getRequirements();
155                 List<Map<String, ToscaRequirement>> toscaRequirements = new ArrayList<>();
156                 if (requirements != null) {
157                         boolean isNodeType = ModelConverter.isAtomicComponent(component);
158                         for (Map.Entry<String, List<RequirementDefinition>> entry : requirements.entrySet()) {
159                                 entry.getValue().stream().filter(r -> (!isNodeType || (isNodeType && component.getUniqueId().equals(r.getOwnerId())) || (isNodeType && r.getOwnerId() == null))).forEach(r -> {
160                                         ImmutablePair<String, ToscaRequirement> pair = convertRequirement(component, isNodeType, r);
161                                         Map<String, ToscaRequirement> requirement = new HashMap<>();
162
163                                         requirement.put(pair.left, pair.right);
164                                         toscaRequirements.add(requirement);
165                                 });
166
167                                 log.debug("Finish convert Requirements for node type");
168                         }
169                 } else {
170                         log.debug("No Requirements for node type");
171                 }
172                 return toscaRequirements;
173         }
174
175         private String getSubPathByFirstDelimiterAppearance(String path) {
176                 return path.substring(path.indexOf(PATH_DELIMITER) + 1);
177         }
178         
179         private String getSubPathByLastDelimiterAppearance(String path) {
180                 return path.substring(path.lastIndexOf(PATH_DELIMITER) + 1);
181         }
182         
183         //This function calls on Substitution Mapping region - the component is always non-atomic
184         private Map<String, String[]> convertSubstitutionMappingRequirementsAsMap(Component component) {
185                 Map<String, List<RequirementDefinition>> requirements = component.getRequirements();
186                 Map<String,  String[]> toscaRequirements = new HashMap<>();
187                 if (requirements != null) {
188                         for (Map.Entry<String, List<RequirementDefinition>> entry : requirements.entrySet()) {
189                                 entry.getValue().stream().forEach(r -> {
190                                         String fullReqName;
191                                         String sourceCapName;
192                                         if(ToscaUtils.isComplexVfc(component)){
193                                                 fullReqName = r.getName();
194                                                 sourceCapName = r.getParentName();
195                                         } else {
196                                                 fullReqName = getRequirementPath(component, r);
197                                                 sourceCapName = getSubPathByFirstDelimiterAppearance(fullReqName);
198                                         }
199                                         log.debug("the requirement {} belongs to resource {} ", fullReqName, component.getUniqueId());
200                                         if (sourceCapName != null) {
201                                                 String owner = "";
202
203                                                 List<String> capPath = r.getPath();
204                                                 String lastInPath = capPath.get(capPath.size() - 1);
205                                                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(lastInPath)).findFirst();
206                                                 if (findFirst.isPresent()) {
207                                                         owner = findFirst.get().getNormalizedName();
208                                                 }
209
210                                                 toscaRequirements.put(fullReqName, new String[] { owner, sourceCapName });
211                                         }
212                                 });
213                                 log.debug("Finish convert Requirements for node type");
214                         }
215                 } else {
216                         log.debug("No Requirements for node type");
217                 }
218                 return toscaRequirements;
219         }
220
221         private String getRequirementPath(Component component, RequirementDefinition r) {
222                         
223                 // Evg : for the last in path take real instance name and not "decrypt" unique id. ( instance name can be change and not equal to id..)
224                 // dirty quick fix. must be changed as capability redesign
225                 List<String> capPath = r.getPath();
226                 String lastInPath = capPath.get(capPath.size() - 1);
227                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(lastInPath)).findFirst();
228                 if (findFirst.isPresent()) {
229                         String LastInPathName = findFirst.get().getNormalizedName();
230
231                         if (capPath.size() > 1) {
232                                 List<String> pathArray = Lists.reverse(capPath.stream().map(path -> ValidationUtils.normalizeComponentInstanceName(getSubPathByLastDelimiterAppearance(path))).collect(Collectors.toList()));
233
234                                 return new StringBuilder().append(LastInPathName).append(PATH_DELIMITER).append(String.join(PATH_DELIMITER, pathArray.subList(1, pathArray.size() ))).append(PATH_DELIMITER).append(r.getName()).toString();
235                         }else{
236                                 return new StringBuilder().append(LastInPathName).append(PATH_DELIMITER).append(r.getName()).toString();
237                         }
238                 }
239                 return "";
240         }
241
242         private ImmutablePair<String, ToscaRequirement> convertRequirement(Component component, boolean isNodeType, RequirementDefinition r) {
243                 String name = r.getName();
244                 if (!isNodeType) {
245                         name = getRequirementPath(component, r);
246                 }
247                 log.debug("the requirement {} belongs to resource {} ", name, component.getUniqueId());
248                 ToscaRequirement toscaRequirement = new ToscaRequirement();
249
250                 List<Object> occurences = new ArrayList<>();
251                 occurences.add(Integer.valueOf(r.getMinOccurrences()));
252                 if (r.getMaxOccurrences().equals(RequirementDataDefinition.MAX_OCCURRENCES)) {
253                         occurences.add(r.getMaxOccurrences());
254                 } else {
255                         occurences.add(Integer.valueOf(r.getMaxOccurrences()));
256                 }
257                 toscaRequirement.setOccurrences(occurences);
258                 // toscaRequirement.setOccurrences(createOcurrencesRange(requirementDefinition.getMinOccurrences(),
259                 // requirementDefinition.getMaxOccurrences()));
260                 toscaRequirement.setNode(r.getNode());
261                 toscaRequirement.setCapability(r.getCapability());
262                 toscaRequirement.setRelationship(r.getRelationship());
263
264                 ImmutablePair<String, ToscaRequirement> pair = new ImmutablePair<String, ToscaRequirement>(name, toscaRequirement);
265                 return pair;
266         }
267
268         public Map<String, ToscaCapability> convertCapabilities(Component component, Map<String, DataTypeDefinition> dataTypes) {
269                 Map<String, List<CapabilityDefinition>> capabilities = component.getCapabilities();
270                 Map<String, ToscaCapability> toscaCapabilities = new HashMap<>();
271                 if (capabilities != null) {
272                         boolean isNodeType = ModelConverter.isAtomicComponent(component);
273                         for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
274                                 entry.getValue().stream().filter(c -> (!isNodeType || (isNodeType && component.getUniqueId().equals(c.getOwnerId())) || (isNodeType && c.getOwnerId() == null) )).forEach(c -> {
275                                         convertCapabilty(component, toscaCapabilities, isNodeType, c, dataTypes);
276
277                                 });
278                         }
279                 } else {
280                         log.debug("No Capabilities for node type");
281                 }
282
283                 return toscaCapabilities;
284         }
285
286         public Map<String, ToscaCapability> convertProxyCapabilities(Component component, Component proxyComponent, ComponentInstance instanceProxy, Map<String, DataTypeDefinition> dataTypes) {
287                 Map<String, List<CapabilityDefinition>> capabilities = instanceProxy.getCapabilities();
288                 Map<String, ToscaCapability> toscaCapabilities = new HashMap<>();
289                 if (capabilities != null) {
290                         boolean isNodeType = ModelConverter.isAtomicComponent(component);
291                         for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
292                                 entry.getValue().stream().forEach(c -> {
293                                         convertCapabilty(proxyComponent, toscaCapabilities, isNodeType, c, dataTypes);
294
295                                 });
296                         }
297                 } else {
298                         log.debug("No Capabilities for node type");
299                 }
300
301                 return toscaCapabilities;
302         }
303
304         // This function calls on Substitution Mapping region - the component is always non-atomic
305         public Map<String, String[]> convertSubstitutionMappingCapabilities(Component component, Map<String, DataTypeDefinition> dataTypes) {
306                 Map<String, List<CapabilityDefinition>> capabilities = component.getCapabilities();
307                 Map<String, String[]> toscaCapabilities = new HashMap<>();
308                 if (capabilities != null) {
309                         for (Map.Entry<String, List<CapabilityDefinition>> entry : capabilities.entrySet()) {
310                                 entry.getValue().stream().forEach(c -> {
311                                         String fullCapName;
312                                         String sourceReqName;
313                                         if (ToscaUtils.isComplexVfc(component)) {
314                                                 fullCapName = c.getName();
315                                                 sourceReqName = c.getParentName();
316                                         } else {
317                                                 fullCapName = getCapabilityPath(c, component);
318                                                 sourceReqName = getSubPathByFirstDelimiterAppearance(fullCapName);
319                                         }
320                                         log.debug("the capabilty {} belongs to resource {} ", fullCapName, component.getUniqueId());
321                                         if (sourceReqName != null) {
322                                                 String owner = "";
323
324                                                 List<String> capPath = c.getPath();
325                                                 String lastInPath = capPath.get(capPath.size() - 1);
326                                                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(lastInPath)).findFirst();
327                                                 if (findFirst.isPresent()) {
328                                                         owner = findFirst.get().getNormalizedName();
329                                                 }
330                                                 toscaCapabilities.put(fullCapName, new String[] { owner, sourceReqName });
331                                         }
332                                 });
333                         }
334                 } else {
335                         log.debug("No Capabilities for node type");
336                 }
337
338                 return toscaCapabilities;
339         }
340
341         private String getCapabilityPath(CapabilityDefinition c, Component component) {
342                 // Evg : for the last in path take real instance name and not "decrypt" unique id. ( instance name can be change and not equal to id..)
343                 // dirty quick fix. must be changed as capability redesign
344                 List<String> capPath = c.getPath();
345                 String lastInPath = capPath.get(capPath.size() - 1);
346                 Optional<ComponentInstance> findFirst = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(lastInPath)).findFirst();
347                 if (findFirst.isPresent()) {
348                         String LastInPathName = findFirst.get().getNormalizedName();
349
350                         if (capPath.size() > 1) {
351                                 List<String> pathArray = Lists.reverse(capPath.stream().map(path -> ValidationUtils.normalizeComponentInstanceName(getSubPathByLastDelimiterAppearance(path))).collect(Collectors.toList()));
352
353                                 return new StringBuilder().append(LastInPathName).append(PATH_DELIMITER).append(String.join(PATH_DELIMITER, pathArray.subList(1, pathArray.size() ))).append(PATH_DELIMITER).append(c.getName()).toString();
354                         }else{
355                                 return new StringBuilder().append(LastInPathName).append(PATH_DELIMITER).append(c.getName()).toString();
356                         }
357                 }
358                 return "";
359         }
360
361         private void convertCapabilty(Component component, Map<String, ToscaCapability> toscaCapabilities, boolean isNodeType, CapabilityDefinition c, Map<String, DataTypeDefinition> dataTypes) {
362                 String name = c.getName();
363                 if (!isNodeType) {
364                         name = getCapabilityPath(c, component);
365                 }
366                 log.debug("the capabilty {} belongs to resource {} ", name, component.getUniqueId());
367                 ToscaCapability toscaCapability = new ToscaCapability();
368                 toscaCapability.setDescription(c.getDescription());
369                 toscaCapability.setType(c.getType());
370
371                 List<Object> occurences = new ArrayList<>();
372                 occurences.add(Integer.valueOf(c.getMinOccurrences()));
373                 if (c.getMaxOccurrences().equals(CapabilityDataDefinition.MAX_OCCURRENCES)) {
374                         occurences.add(c.getMaxOccurrences());
375                 } else {
376                         occurences.add(Integer.valueOf(c.getMaxOccurrences()));
377                 }
378                 toscaCapability.setOccurrences(occurences);
379
380                 toscaCapability.setValid_source_types(c.getValidSourceTypes());
381                 List<ComponentInstanceProperty> properties = c.getProperties();
382                 if (properties != null && !properties.isEmpty()) {
383                         Map<String, ToscaProperty> toscaProperties = new HashMap<>();
384                         for (PropertyDefinition property : properties) {
385                                 ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, true);
386                                 toscaProperties.put(property.getName(), toscaProperty);
387                         }
388                         toscaCapability.setProperties(toscaProperties);
389                 }
390                 toscaCapabilities.put(name, toscaCapability);
391         }
392
393 }