3 * ============LICENSE_START=======================================================
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.openecomp.sdc.be.tosca;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
28 import java.util.Optional;
29 import java.util.stream.Collectors;
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;
53 import com.google.common.collect.Lists;
55 import fj.data.Either;
57 public class CapabiltyRequirementConvertor {
58 private static CapabiltyRequirementConvertor instance;
59 public final static String PATH_DELIMITER = ".";
61 protected CapabiltyRequirementConvertor() {
65 public static synchronized CapabiltyRequirementConvertor getInstance() {
66 if (instance == null) {
67 instance = new CapabiltyRequirementConvertor();
72 private static Logger log = LoggerFactory.getLogger(CapabiltyRequirementConvertor.class.getName());
74 public Either<ToscaNodeTemplate, ToscaError> convertComponentInstanceCapabilties(ComponentInstance componentInstance, Map<String, DataTypeDefinition> dataTypes, ToscaNodeTemplate nodeTemplate) {
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);
87 if (capabilties != null && !capabilties.isEmpty()) {
88 nodeTemplate.setCapabilities(capabilties);
91 return Either.left(nodeTemplate);
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);
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());
107 ToscaTemplateCapability toscaTemplateCapability = capabilties.get(c.getName());
108 if (toscaTemplateCapability == null) {
109 toscaTemplateCapability = new ToscaTemplateCapability();
110 capabilties.put(c.getName(), toscaTemplateCapability);
112 Map<String, Object> toscaCapProp = toscaTemplateCapability.getProperties();
113 if (toscaCapProp == null) {
114 toscaCapProp = new HashMap<>();
116 Object convertedValue = convertInstanceProperty(dataTypes, componentInstance, p);
117 toscaCapProp.put(p.getName(), convertedValue);
118 toscaTemplateCapability.setProperties(toscaCapProp);
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();
128 String propValue = prop.getValue() == null ? prop.getDefaultValue() : prop.getValue();
129 Object convertedValue = PropertyConvertor.getInstance().convertToToscaObject(propertyType, propValue, innerType, dataTypes);
130 return convertedValue;
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);
138 log.debug("Finish convert Requirements for node type");
140 return Either.left(nodeType);
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);
148 log.debug("Finish convert Requirements for node type");
150 return Either.left(substitutionMapping);
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<>();
163 requirement.put(pair.left, pair.right);
164 toscaRequirements.add(requirement);
167 log.debug("Finish convert Requirements for node type");
170 log.debug("No Requirements for node type");
172 return toscaRequirements;
175 private String getSubPathByFirstDelimiterAppearance(String path) {
176 return path.substring(path.indexOf(PATH_DELIMITER) + 1);
179 private String getSubPathByLastDelimiterAppearance(String path) {
180 return path.substring(path.lastIndexOf(PATH_DELIMITER) + 1);
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 -> {
191 String sourceCapName;
192 if(ToscaUtils.isComplexVfc(component)){
193 fullReqName = r.getName();
194 sourceCapName = r.getParentName();
196 fullReqName = getRequirementPath(component, r);
197 sourceCapName = getSubPathByFirstDelimiterAppearance(fullReqName);
199 log.debug("the requirement {} belongs to resource {} ", fullReqName, component.getUniqueId());
200 if (sourceCapName != null) {
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();
210 toscaRequirements.put(fullReqName, new String[] { owner, sourceCapName });
213 log.debug("Finish convert Requirements for node type");
216 log.debug("No Requirements for node type");
218 return toscaRequirements;
221 private String getRequirementPath(Component component, RequirementDefinition r) {
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();
231 if (capPath.size() > 1) {
232 List<String> pathArray = Lists.reverse(capPath.stream().map(path -> ValidationUtils.normalizeComponentInstanceName(getSubPathByLastDelimiterAppearance(path))).collect(Collectors.toList()));
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();
236 return new StringBuilder().append(LastInPathName).append(PATH_DELIMITER).append(r.getName()).toString();
242 private ImmutablePair<String, ToscaRequirement> convertRequirement(Component component, boolean isNodeType, RequirementDefinition r) {
243 String name = r.getName();
245 name = getRequirementPath(component, r);
247 log.debug("the requirement {} belongs to resource {} ", name, component.getUniqueId());
248 ToscaRequirement toscaRequirement = new ToscaRequirement();
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());
255 occurences.add(Integer.valueOf(r.getMaxOccurrences()));
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());
264 ImmutablePair<String, ToscaRequirement> pair = new ImmutablePair<String, ToscaRequirement>(name, toscaRequirement);
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);
280 log.debug("No Capabilities for node type");
283 return toscaCapabilities;
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);
298 log.debug("No Capabilities for node type");
301 return toscaCapabilities;
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 -> {
312 String sourceReqName;
313 if (ToscaUtils.isComplexVfc(component)) {
314 fullCapName = c.getName();
315 sourceReqName = c.getParentName();
317 fullCapName = getCapabilityPath(c, component);
318 sourceReqName = getSubPathByFirstDelimiterAppearance(fullCapName);
320 log.debug("the capabilty {} belongs to resource {} ", fullCapName, component.getUniqueId());
321 if (sourceReqName != null) {
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();
330 toscaCapabilities.put(fullCapName, new String[] { owner, sourceReqName });
335 log.debug("No Capabilities for node type");
338 return toscaCapabilities;
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();
350 if (capPath.size() > 1) {
351 List<String> pathArray = Lists.reverse(capPath.stream().map(path -> ValidationUtils.normalizeComponentInstanceName(getSubPathByLastDelimiterAppearance(path))).collect(Collectors.toList()));
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();
355 return new StringBuilder().append(LastInPathName).append(PATH_DELIMITER).append(c.getName()).toString();
361 private void convertCapabilty(Component component, Map<String, ToscaCapability> toscaCapabilities, boolean isNodeType, CapabilityDefinition c, Map<String, DataTypeDefinition> dataTypes) {
362 String name = c.getName();
364 name = getCapabilityPath(c, component);
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());
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());
376 occurences.add(Integer.valueOf(c.getMaxOccurrences()));
378 toscaCapability.setOccurrences(occurences);
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);
388 toscaCapability.setProperties(toscaProperties);
390 toscaCapabilities.put(name, toscaCapability);