2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.be.model.operations.impl;
23 import com.google.common.annotations.VisibleForTesting;
24 import com.google.common.base.Strings;
25 import fj.data.Either;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
28 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
29 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
30 import org.openecomp.sdc.be.dao.neo4j.GraphEdgePropertiesDictionary;
31 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
32 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
33 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
34 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
35 import org.openecomp.sdc.be.model.CapabilityDefinition;
36 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
37 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
38 import org.openecomp.sdc.be.model.PropertyDefinition;
39 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
40 import org.openecomp.sdc.be.resources.data.CapabilityData;
41 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
42 import org.openecomp.sdc.be.resources.data.PropertyData;
43 import org.openecomp.sdc.be.resources.data.PropertyValueData;
44 import org.openecomp.sdc.common.log.wrappers.Logger;
45 import org.springframework.stereotype.Component;
48 import java.util.function.Function;
49 import java.util.stream.Collectors;
51 import static org.springframework.util.CollectionUtils.isEmpty;
53 @Component("capability-operation")
54 public class CapabilityOperation extends AbstractOperation {
57 private static final Logger log = Logger.getLogger(CapabilityOperation.class.getName());
59 private final CapabilityTypeOperation capabilityTypeOperation;
60 private final PropertyOperation propertyOperation;
63 public CapabilityOperation(CapabilityTypeOperation capabilityTypeOperation, PropertyOperation propertyOperation) {
64 this.capabilityTypeOperation = capabilityTypeOperation;
65 this.propertyOperation = propertyOperation;
70 public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
71 this.titanGenericDao = titanGenericDao;
74 public Either<CapabilityData, TitanOperationStatus> addCapabilityToGraph(String resourceId, CapabilityTypeData capTypeData, CapabilityDefinition capabilityDefinition) {
76 log.debug("#addCapabilityToGraph - capabilityDefinition={}", capabilityDefinition);
78 String capUniqueId = UniqueIdBuilder.buildCapabilityUid(resourceId, capabilityDefinition.getName());
79 CapabilityData capabilityData = buildCapabilityData(capabilityDefinition, capUniqueId);
81 log.debug("addCapabilityToGraph - Before adding capability to graph. capabilityTypeData = {}", capabilityData);
82 Either<CapabilityData, TitanOperationStatus> createCapResult = titanGenericDao.createNode(capabilityData, CapabilityData.class);
83 log.debug("addCapabilityToGraph - After adding capability to graph. status is = {}", createCapResult);
85 if (createCapResult.isRight()) {
86 TitanOperationStatus operationStatus = createCapResult.right().value();
87 log.error("addCapabilityToGraph - Failed to add capability of type {} to graph. status is {}", capabilityDefinition.getType(), operationStatus);
88 return createCapResult;
91 createCapResult = connectToCapabilityType(capabilityData, capTypeData)
93 .bind(res -> createCapabilityProperties(capabilityData, capTypeData))
95 .map(res -> capabilityData);
97 return createCapResult;
100 private Either<GraphRelation, TitanOperationStatus> connectToCapabilityType(CapabilityData capabilityData, CapabilityTypeData capabilityTypeData) {
102 Map<String, Object> properties = new HashMap<>();
104 String capabilityName = capabilityData.getCapabilityDataDefinition().getName();
105 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), capabilityName);
107 return titanGenericDao.createRelation(capabilityData, capabilityTypeData, GraphEdgeLabels.CAPABILITY_IMPL, properties);
116 public Either<List<CapabilityDefinition>, TitanOperationStatus> getCapabilitiesWithProps(List<ImmutablePair<CapabilityData, GraphEdge>> capabilites) {
117 List<Either<CapabilityDefinition, TitanOperationStatus>> listFilledCapabilitiesResults = capabilites.stream()
118 .map(ImmutablePair::getLeft)
119 .map(this::toCapabilityDefinitionWithProps)
120 .collect(Collectors.toList());
122 Optional<TitanOperationStatus> status = listFilledCapabilitiesResults.stream().filter(Either::isRight)
123 .map(res -> res.right().value())
126 if (status.isPresent()) {
127 return Either.right(status.get());
130 List<CapabilityDefinition> listCapabilities = listFilledCapabilitiesResults.stream()
131 .map(res -> res.left().value())
132 .collect(Collectors.toList());
134 return Either.left(listCapabilities);
137 private Either<CapabilityDefinition, TitanOperationStatus> toCapabilityDefinitionWithProps(CapabilityData capabilityData) {
138 CapabilityDefinition capabilityDefinition = new CapabilityDefinition(capabilityData.getCapabilityDataDefinition());
139 return getCapabilityProperties(capabilityDefinition.getUniqueId(), capabilityDefinition.getType())
142 capabilityDefinition.setProperties(props);
143 return capabilityDefinition;
149 * get all properties of the capability.
151 * the property definition is taken from the capability type.
153 * @param capabilityUid
156 private Either<List<ComponentInstanceProperty>, TitanOperationStatus> getCapabilityProperties(String capabilityUid, String capabilityType) {
157 Either<CapabilityTypeDefinition, TitanOperationStatus> capabilityTypeRes = capabilityTypeOperation.getCapabilityTypeByType(capabilityType);
159 if (capabilityTypeRes.isRight()) {
160 TitanOperationStatus status = capabilityTypeRes.right().value();
161 return Either.right(status);
164 CapabilityTypeDefinition capabilityTypeDefinition = capabilityTypeRes.left().value();
166 Either<Map<String, PropertyDefinition>, TitanOperationStatus> typesPropsRes = getPropertiesOfCapabilityTypeAndAcestors(capabilityTypeDefinition);
167 if (typesPropsRes.isRight()) {
168 TitanOperationStatus status = typesPropsRes.right().value();
169 return Either.right(status);
172 Map<String, PropertyDefinition> capabilityTypeProperties = typesPropsRes.left().value();
174 if (isEmpty(capabilityTypeProperties)) {
175 return Either.right(TitanOperationStatus.OK);
178 Map<String, PropertyDefinition> uidToPropDefMap = capabilityTypeProperties.values().stream()
179 .collect(Collectors.toMap(PropertyDefinition::getUniqueId, Function.identity()));
181 // Find all properties values on the capability
182 Either<List<ImmutablePair<PropertyValueData, GraphEdge>>, TitanOperationStatus> propertyValNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Capability), capabilityUid, GraphEdgeLabels.PROPERTY_VALUE,
183 NodeTypeEnum.PropertyValue, PropertyValueData.class);
185 if (propertyValNodes.isRight()) {
186 return onLoadPropValuesFailure(propertyValNodes.right().value(), capabilityTypeProperties);
189 List<ImmutablePair<PropertyValueData, GraphEdge>> propValsRelationPairs = propertyValNodes.left().value();
190 if (isEmpty(propValsRelationPairs)) {
191 return Either.right(TitanOperationStatus.OK);
194 List<ComponentInstanceProperty> capabilityProperties = new ArrayList<>();
196 for (ImmutablePair<PropertyValueData, GraphEdge> propValRelPair : propValsRelationPairs) {
198 PropertyValueData propertyValueData = propValRelPair.getLeft();
199 Either<ImmutablePair<PropertyData, GraphEdge>, TitanOperationStatus> propertyDefRes = titanGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.PropertyValue), propertyValueData.getUniqueId(), GraphEdgeLabels.PROPERTY_IMPL,
200 NodeTypeEnum.Property, PropertyData.class);
201 if (propertyDefRes.isRight()) {
202 TitanOperationStatus status = propertyDefRes.right().value();
203 if (status == TitanOperationStatus.NOT_FOUND) {
204 status = TitanOperationStatus.INVALID_ID;
206 return Either.right(status);
209 ImmutablePair<PropertyData, GraphEdge> propertyDefPair = propertyDefRes.left().value();
210 PropertyData propertyData = propertyDefPair.left;
211 String propertyUniqueId = propertyData.getPropertyDataDefinition().getUniqueId();
213 PropertyDefinition propertyDefinition = uidToPropDefMap.get(propertyUniqueId);
214 ComponentInstanceProperty capabilityProperty = new ComponentInstanceProperty(propertyDefinition, propertyValueData.getValue(), propertyValueData.getUniqueId());
216 capabilityProperties.add(capabilityProperty);
219 Set<String> processedProps = buildProcessedPropsSet(capabilityProperties);
221 // Find all properties which does not have property value on the group.
222 List<ComponentInstanceProperty> leftProps = filterCapabilityTypesProps(capabilityTypeProperties, processedProps);
223 if (leftProps != null) {
224 capabilityProperties.addAll(leftProps);
227 return Either.left(capabilityProperties);
232 * @param capabilityProperties
235 private Set<String> buildProcessedPropsSet(List<ComponentInstanceProperty> capabilityProperties) {
236 return capabilityProperties.stream()
237 .map(ComponentInstanceProperty::getName)
238 .collect(Collectors.toSet());
241 private Either<List<ComponentInstanceProperty>, TitanOperationStatus> onLoadPropValuesFailure(TitanOperationStatus status, Map<String, PropertyDefinition> capabilityTypeProperties) {
242 if (status == TitanOperationStatus.NOT_FOUND) {
243 return Either.left(buildPropsFromCapabilityTypeProps(capabilityTypeProperties));
245 return Either.right(status);
251 * @param capabilityTypeProperties
254 private List<ComponentInstanceProperty> buildPropsFromCapabilityTypeProps(Map<String, PropertyDefinition> capabilityTypeProperties) {
255 return capabilityTypeProperties.values().stream()
256 .map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null))
257 .collect(Collectors.toList());
262 * @param capabilityTypeRes
263 * @param capabilityTypeDefinition
266 private Either<Map<String, PropertyDefinition>, TitanOperationStatus> getPropertiesOfCapabilityTypeAndAcestors(CapabilityTypeDefinition capabilityTypeDefinition) {
267 // Get the properties on the group type of this capability
268 Map<String, PropertyDefinition> capabilityTypeProperties = capabilityTypeDefinition.getProperties();
270 String derivedFrom = capabilityTypeDefinition.getDerivedFrom();
271 if (!Strings.isNullOrEmpty(derivedFrom)) {
272 Either<Map<String, PropertyDefinition>, TitanOperationStatus> parentPropsRes = capabilityTypeOperation.getAllCapabilityTypePropertiesFromAllDerivedFrom(derivedFrom);
273 if(parentPropsRes.isRight()) {
274 TitanOperationStatus status = parentPropsRes.right().value();
275 return Either.right(status);
277 if (capabilityTypeProperties != null) {
278 capabilityTypeProperties.putAll(parentPropsRes.left().value());
280 capabilityTypeProperties = parentPropsRes.left().value();
284 return Either.left(capabilityTypeProperties);
289 * Create all property values of the capability and their
290 * relations to relevant properties of the capability type.
292 * @param capabilityDefintion
293 * @param capabilityTypeData
296 private Either<List<ComponentInstanceProperty>, TitanOperationStatus> createCapabilityProperties(CapabilityData capabilityData,
297 CapabilityTypeData capabilityTypeData) {
299 CapabilityDefinition capabilityDefintion = (CapabilityDefinition)capabilityData.getCapabilityDataDefinition();
300 CapabilityTypeDefinition capabilityTypeDefinition = (CapabilityTypeDefinition)capabilityTypeData.getCapabilityTypeDataDefinition();
302 Either<Map<String, PropertyDefinition>, TitanOperationStatus> typesPropsRes = getPropertiesOfCapabilityTypeAndAcestors(capabilityTypeDefinition);
303 if (typesPropsRes.isRight()) {
304 TitanOperationStatus status = typesPropsRes.right().value();
305 return Either.right(status);
308 Map<String, PropertyDefinition> capabilityTypeProperties = typesPropsRes.left().value();
310 if (isEmpty(capabilityTypeProperties) && !isEmpty(capabilityDefintion.getProperties())) {
311 log.debug("#createCapabilityProperties - It's not valid if group capability has properties while corresponding capability type doesn't.");
312 return Either.right(TitanOperationStatus.MATCH_NOT_FOUND);
315 Optional<TitanOperationStatus> error = capabilityDefintion.getProperties().stream()
316 .map(property -> createPropertyValue(property, capabilityData, capabilityTypeProperties.get(property.getName())))
317 .filter(Either::isRight)
318 .map(result -> result.right().value())
320 if (error.isPresent()) {
321 return Either.right(error.get());
324 return Either.left(capabilityDefintion.getProperties());
329 * @param capabilityTypeProperties
330 * @param excludePropsWithUniqueIds
333 private List<ComponentInstanceProperty> filterCapabilityTypesProps(Map<String, PropertyDefinition> capabilityTypeProperties,
334 Set<String> excludePropsWithNames) {
335 return capabilityTypeProperties.values().stream()
336 .filter(p -> !excludePropsWithNames.contains(p.getName()))
337 .map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null))
338 .collect(Collectors.toList());
341 private Either<PropertyValueData, TitanOperationStatus> createPropertyValue(ComponentInstanceProperty capabilityProperty,
342 CapabilityData capabilityData,
343 PropertyDefinition capTypePropertyDefinition) {
344 if (capTypePropertyDefinition == null) {
345 return Either.right(TitanOperationStatus.MATCH_NOT_FOUND);
348 CapabilityDefinition capabilityDefintion = (CapabilityDefinition)capabilityData.getCapabilityDataDefinition();
350 Either<Integer, StorageOperationStatus> indexRes =
351 propertyOperation.increaseAndGetObjInstancePropertyCounter(capabilityDefintion.getUniqueId(), NodeTypeEnum.Capability);
352 String uniqueId = UniqueIdBuilder.buildResourceInstancePropertyValueUid(capabilityDefintion.getUniqueId(), indexRes.left().value() );
353 PropertyValueData propertyValueData = new PropertyValueData();
354 propertyValueData.setUniqueId(uniqueId);
355 propertyValueData.setValue(capabilityProperty.getValue());
356 Either<PropertyValueData, TitanOperationStatus> propResult = titanGenericDao.createNode(propertyValueData, PropertyValueData.class);
357 // It's not accepted if Capability Type doesn't have suitable property
358 propResult = propResult.left()
359 .bind(propValueData -> connectToProperty(propValueData, capTypePropertyDefinition))
361 .bind(graphRelation -> connectCapability(propertyValueData, capTypePropertyDefinition.getName(), capabilityData))
363 .map(graphRelation -> propertyValueData);
366 .foreachDoEffect(propValueData -> capabilityProperty.setUniqueId(uniqueId));
371 private Either<GraphRelation, TitanOperationStatus> connectCapability(PropertyValueData propValueData, String name, CapabilityData capabilityData) {
372 Map<String, Object> properties = new HashMap<>();
373 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), name);
375 return titanGenericDao.createRelation(capabilityData, propValueData, GraphEdgeLabels.PROPERTY_VALUE, properties);
378 private Either<GraphRelation, TitanOperationStatus> connectToProperty(PropertyValueData propValueData, PropertyDefinition propertyDefinition) {
379 Either<PropertyData, TitanOperationStatus> dataTypesRes = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Property),
380 propertyDefinition.getUniqueId(), PropertyData.class);
382 Map<String, Object> properties = new HashMap<>();
383 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), propertyDefinition.getName());
385 return dataTypesRes.left()
386 .bind(propertyData -> titanGenericDao.createRelation(propValueData, propertyData, GraphEdgeLabels.PROPERTY_IMPL, properties));
390 private CapabilityData buildCapabilityData(CapabilityDefinition capabilityDefinition, String ctUniqueId) {
392 CapabilityData capabilityData = new CapabilityData(capabilityDefinition);
394 capabilityData.setUniqueId(ctUniqueId);
395 Long creationDate = capabilityData.getCreationTime();
396 if (creationDate == null) {
397 creationDate = System.currentTimeMillis();
399 capabilityData.setCreationTime(creationDate);
400 capabilityData.setModificationTime(creationDate);
401 return capabilityData;
405 public StorageOperationStatus deleteCapability(CapabilityDefinition capabilityDef) {
407 return titanGenericDao.deleteChildrenNodes(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), capabilityDef.getUniqueId(), GraphEdgeLabels.PROPERTY_VALUE,
408 NodeTypeEnum.PropertyValue, PropertyValueData.class)
410 .bind(props -> titanGenericDao.deleteNode(new CapabilityData(capabilityDef), CapabilityData.class))
412 .map(DaoStatusConverter::convertTitanStatusToStorageStatus)
414 .on(capData -> StorageOperationStatus.OK);