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 static org.springframework.util.CollectionUtils.isEmpty;
25 import com.google.common.annotations.VisibleForTesting;
26 import com.google.common.base.Strings;
27 import fj.data.Either;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
32 import java.util.Optional;
34 import java.util.function.Function;
35 import java.util.stream.Collectors;
36 import org.apache.commons.lang3.tuple.ImmutablePair;
37 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
38 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
39 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
40 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
41 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
42 import org.openecomp.sdc.be.dao.neo4j.GraphEdgePropertiesDictionary;
43 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
44 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
45 import org.openecomp.sdc.be.model.CapabilityDefinition;
46 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
47 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
48 import org.openecomp.sdc.be.model.PropertyDefinition;
49 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
50 import org.openecomp.sdc.be.resources.data.CapabilityData;
51 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
52 import org.openecomp.sdc.be.resources.data.PropertyData;
53 import org.openecomp.sdc.be.resources.data.PropertyValueData;
54 import org.openecomp.sdc.common.log.wrappers.Logger;
55 import org.springframework.stereotype.Component;
57 @Component("capability-operation")
58 public class CapabilityOperation extends AbstractOperation {
61 private static final Logger log = Logger.getLogger(CapabilityOperation.class.getName());
63 private final CapabilityTypeOperation capabilityTypeOperation;
64 private final PropertyOperation propertyOperation;
67 public CapabilityOperation(CapabilityTypeOperation capabilityTypeOperation, PropertyOperation propertyOperation) {
68 this.capabilityTypeOperation = capabilityTypeOperation;
69 this.propertyOperation = propertyOperation;
74 public void setJanusGraphGenericDao(HealingJanusGraphGenericDao janusGraphGenericDao) {
75 this.janusGraphGenericDao = janusGraphGenericDao;
78 public Either<CapabilityData, JanusGraphOperationStatus> addCapabilityToGraph(String resourceId, CapabilityTypeData capTypeData, CapabilityDefinition capabilityDefinition) {
80 log.debug("#addCapabilityToGraph - capabilityDefinition={}", capabilityDefinition);
82 String capUniqueId = UniqueIdBuilder.buildCapabilityUid(resourceId, capabilityDefinition.getName());
83 CapabilityData capabilityData = buildCapabilityData(capabilityDefinition, capUniqueId);
85 log.debug("addCapabilityToGraph - Before adding capability to graph. capabilityTypeData = {}", capabilityData);
86 Either<CapabilityData, JanusGraphOperationStatus> createCapResult = janusGraphGenericDao
87 .createNode(capabilityData, CapabilityData.class);
88 log.debug("addCapabilityToGraph - After adding capability to graph. status is = {}", createCapResult);
90 if (createCapResult.isRight()) {
91 JanusGraphOperationStatus operationStatus = createCapResult.right().value();
92 log.error("addCapabilityToGraph - Failed to add capability of type {} to graph. status is {}", capabilityDefinition.getType(), operationStatus);
93 return createCapResult;
96 createCapResult = connectToCapabilityType(capabilityData, capTypeData)
98 .bind(res -> createCapabilityProperties(capabilityData, capTypeData))
100 .map(res -> capabilityData);
102 return createCapResult;
105 private Either<GraphRelation, JanusGraphOperationStatus> connectToCapabilityType(CapabilityData capabilityData, CapabilityTypeData capabilityTypeData) {
107 Map<String, Object> properties = new HashMap<>();
109 String capabilityName = capabilityData.getCapabilityDataDefinition().getName();
110 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), capabilityName);
112 return janusGraphGenericDao
113 .createRelation(capabilityData, capabilityTypeData, GraphEdgeLabels.CAPABILITY_IMPL, properties);
122 public Either<List<CapabilityDefinition>, JanusGraphOperationStatus> getCapabilitiesWithProps(List<ImmutablePair<CapabilityData, GraphEdge>> capabilites) {
123 List<Either<CapabilityDefinition, JanusGraphOperationStatus>> listFilledCapabilitiesResults = capabilites.stream()
124 .map(ImmutablePair::getLeft)
125 .map(this::toCapabilityDefinitionWithProps)
126 .collect(Collectors.toList());
128 Optional<JanusGraphOperationStatus> status = listFilledCapabilitiesResults.stream().filter(Either::isRight)
129 .map(res -> res.right().value())
132 if (status.isPresent()) {
133 return Either.right(status.get());
136 List<CapabilityDefinition> listCapabilities = listFilledCapabilitiesResults.stream()
137 .map(res -> res.left().value())
138 .collect(Collectors.toList());
140 return Either.left(listCapabilities);
143 private Either<CapabilityDefinition, JanusGraphOperationStatus> toCapabilityDefinitionWithProps(CapabilityData capabilityData) {
144 CapabilityDefinition capabilityDefinition = new CapabilityDefinition(capabilityData.getCapabilityDataDefinition());
145 return getCapabilityProperties(capabilityDefinition.getUniqueId(), capabilityDefinition.getType())
148 capabilityDefinition.setProperties(props);
149 return capabilityDefinition;
155 * get all properties of the capability.
157 * the property definition is taken from the capability type.
159 * @param capabilityUid
162 private Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> getCapabilityProperties(String capabilityUid, String capabilityType) {
163 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> capabilityTypeRes = capabilityTypeOperation.getCapabilityTypeByType(capabilityType);
165 if (capabilityTypeRes.isRight()) {
166 JanusGraphOperationStatus status = capabilityTypeRes.right().value();
167 return Either.right(status);
170 CapabilityTypeDefinition capabilityTypeDefinition = capabilityTypeRes.left().value();
172 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> typesPropsRes = getPropertiesOfCapabilityTypeAndAcestors(capabilityTypeDefinition);
173 if (typesPropsRes.isRight()) {
174 JanusGraphOperationStatus status = typesPropsRes.right().value();
175 return Either.right(status);
178 Map<String, PropertyDefinition> capabilityTypeProperties = typesPropsRes.left().value();
180 if (isEmpty(capabilityTypeProperties)) {
181 return Either.right(JanusGraphOperationStatus.OK);
184 Map<String, PropertyDefinition> uidToPropDefMap = capabilityTypeProperties.values().stream()
185 .collect(Collectors.toMap(PropertyDefinition::getUniqueId, Function.identity()));
187 // Find all properties values on the capability
188 Either<List<ImmutablePair<PropertyValueData, GraphEdge>>, JanusGraphOperationStatus> propertyValNodes = janusGraphGenericDao
189 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Capability), capabilityUid, GraphEdgeLabels.PROPERTY_VALUE,
190 NodeTypeEnum.PropertyValue, PropertyValueData.class);
192 if (propertyValNodes.isRight()) {
193 return onLoadPropValuesFailure(propertyValNodes.right().value(), capabilityTypeProperties);
196 List<ImmutablePair<PropertyValueData, GraphEdge>> propValsRelationPairs = propertyValNodes.left().value();
197 if (isEmpty(propValsRelationPairs)) {
198 return Either.right(JanusGraphOperationStatus.OK);
201 List<ComponentInstanceProperty> capabilityProperties = new ArrayList<>();
203 for (ImmutablePair<PropertyValueData, GraphEdge> propValRelPair : propValsRelationPairs) {
205 PropertyValueData propertyValueData = propValRelPair.getLeft();
206 Either<ImmutablePair<PropertyData, GraphEdge>, JanusGraphOperationStatus> propertyDefRes = janusGraphGenericDao
207 .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.PropertyValue), propertyValueData.getUniqueId(), GraphEdgeLabels.PROPERTY_IMPL,
208 NodeTypeEnum.Property, PropertyData.class);
209 if (propertyDefRes.isRight()) {
210 JanusGraphOperationStatus status = propertyDefRes.right().value();
211 if (status == JanusGraphOperationStatus.NOT_FOUND) {
212 status = JanusGraphOperationStatus.INVALID_ID;
214 return Either.right(status);
217 ImmutablePair<PropertyData, GraphEdge> propertyDefPair = propertyDefRes.left().value();
218 PropertyData propertyData = propertyDefPair.left;
219 String propertyUniqueId = propertyData.getPropertyDataDefinition().getUniqueId();
221 PropertyDefinition propertyDefinition = uidToPropDefMap.get(propertyUniqueId);
222 ComponentInstanceProperty capabilityProperty = new ComponentInstanceProperty(propertyDefinition, propertyValueData.getValue(), propertyValueData.getUniqueId());
224 capabilityProperties.add(capabilityProperty);
227 Set<String> processedProps = buildProcessedPropsSet(capabilityProperties);
229 // Find all properties which does not have property value on the group.
230 List<ComponentInstanceProperty> leftProps = filterCapabilityTypesProps(capabilityTypeProperties, processedProps);
231 if (leftProps != null) {
232 capabilityProperties.addAll(leftProps);
235 return Either.left(capabilityProperties);
240 * @param capabilityProperties
243 private Set<String> buildProcessedPropsSet(List<ComponentInstanceProperty> capabilityProperties) {
244 return capabilityProperties.stream()
245 .map(ComponentInstanceProperty::getName)
246 .collect(Collectors.toSet());
249 private Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> onLoadPropValuesFailure(JanusGraphOperationStatus status, Map<String, PropertyDefinition> capabilityTypeProperties) {
250 if (status == JanusGraphOperationStatus.NOT_FOUND) {
251 return Either.left(buildPropsFromCapabilityTypeProps(capabilityTypeProperties));
253 return Either.right(status);
259 * @param capabilityTypeProperties
262 private List<ComponentInstanceProperty> buildPropsFromCapabilityTypeProps(Map<String, PropertyDefinition> capabilityTypeProperties) {
263 return capabilityTypeProperties.values().stream()
264 .map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null))
265 .collect(Collectors.toList());
270 * @param capabilityTypeRes
271 * @param capabilityTypeDefinition
274 private Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getPropertiesOfCapabilityTypeAndAcestors(CapabilityTypeDefinition capabilityTypeDefinition) {
275 // Get the properties on the group type of this capability
276 Map<String, PropertyDefinition> capabilityTypeProperties = capabilityTypeDefinition.getProperties();
278 String derivedFrom = capabilityTypeDefinition.getDerivedFrom();
279 if (!Strings.isNullOrEmpty(derivedFrom)) {
280 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> parentPropsRes = capabilityTypeOperation.getAllCapabilityTypePropertiesFromAllDerivedFrom(derivedFrom);
281 if(parentPropsRes.isRight()) {
282 JanusGraphOperationStatus status = parentPropsRes.right().value();
283 return Either.right(status);
285 if (capabilityTypeProperties != null) {
286 capabilityTypeProperties.putAll(parentPropsRes.left().value());
288 capabilityTypeProperties = parentPropsRes.left().value();
292 return Either.left(capabilityTypeProperties);
297 * Create all property values of the capability and their
298 * relations to relevant properties of the capability type.
300 * @param capabilityDefintion
301 * @param capabilityTypeData
304 private Either<List<ComponentInstanceProperty>, JanusGraphOperationStatus> createCapabilityProperties(CapabilityData capabilityData,
305 CapabilityTypeData capabilityTypeData) {
307 CapabilityDefinition capabilityDefintion = (CapabilityDefinition)capabilityData.getCapabilityDataDefinition();
308 CapabilityTypeDefinition capabilityTypeDefinition = (CapabilityTypeDefinition)capabilityTypeData.getCapabilityTypeDataDefinition();
310 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> typesPropsRes = getPropertiesOfCapabilityTypeAndAcestors(capabilityTypeDefinition);
311 if (typesPropsRes.isRight()) {
312 JanusGraphOperationStatus status = typesPropsRes.right().value();
313 return Either.right(status);
316 Map<String, PropertyDefinition> capabilityTypeProperties = typesPropsRes.left().value();
318 if (isEmpty(capabilityTypeProperties) && !isEmpty(capabilityDefintion.getProperties())) {
319 log.debug("#createCapabilityProperties - It's not valid if group capability has properties while corresponding capability type doesn't.");
320 return Either.right(JanusGraphOperationStatus.MATCH_NOT_FOUND);
323 Optional<JanusGraphOperationStatus> error = capabilityDefintion.getProperties().stream()
324 .map(property -> createPropertyValue(property, capabilityData, capabilityTypeProperties.get(property.getName())))
325 .filter(Either::isRight)
326 .map(result -> result.right().value())
328 if (error.isPresent()) {
329 return Either.right(error.get());
332 return Either.left(capabilityDefintion.getProperties());
337 * @param capabilityTypeProperties
338 * @param excludePropsWithUniqueIds
341 private List<ComponentInstanceProperty> filterCapabilityTypesProps(Map<String, PropertyDefinition> capabilityTypeProperties,
342 Set<String> excludePropsWithNames) {
343 return capabilityTypeProperties.values().stream()
344 .filter(p -> !excludePropsWithNames.contains(p.getName()))
345 .map(p -> new ComponentInstanceProperty(p, p.getDefaultValue(), null))
346 .collect(Collectors.toList());
349 private Either<PropertyValueData, JanusGraphOperationStatus> createPropertyValue(ComponentInstanceProperty capabilityProperty,
350 CapabilityData capabilityData,
351 PropertyDefinition capTypePropertyDefinition) {
352 if (capTypePropertyDefinition == null) {
353 return Either.right(JanusGraphOperationStatus.MATCH_NOT_FOUND);
356 CapabilityDefinition capabilityDefintion = (CapabilityDefinition)capabilityData.getCapabilityDataDefinition();
358 Either<Integer, StorageOperationStatus> indexRes =
359 propertyOperation.increaseAndGetObjInstancePropertyCounter(capabilityDefintion.getUniqueId(), NodeTypeEnum.Capability);
360 String uniqueId = UniqueIdBuilder.buildResourceInstancePropertyValueUid(capabilityDefintion.getUniqueId(), indexRes.left().value() );
361 PropertyValueData propertyValueData = new PropertyValueData();
362 propertyValueData.setUniqueId(uniqueId);
363 propertyValueData.setValue(capabilityProperty.getValue());
364 Either<PropertyValueData, JanusGraphOperationStatus> propResult = janusGraphGenericDao
365 .createNode(propertyValueData, PropertyValueData.class);
366 // It's not accepted if Capability Type doesn't have suitable property
367 propResult = propResult.left()
368 .bind(propValueData -> connectToProperty(propValueData, capTypePropertyDefinition))
370 .bind(graphRelation -> connectCapability(propertyValueData, capTypePropertyDefinition.getName(), capabilityData))
372 .map(graphRelation -> propertyValueData);
375 .foreachDoEffect(propValueData -> capabilityProperty.setUniqueId(uniqueId));
380 private Either<GraphRelation, JanusGraphOperationStatus> connectCapability(PropertyValueData propValueData, String name, CapabilityData capabilityData) {
381 Map<String, Object> properties = new HashMap<>();
382 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), name);
384 return janusGraphGenericDao.createRelation(capabilityData, propValueData, GraphEdgeLabels.PROPERTY_VALUE, properties);
387 private Either<GraphRelation, JanusGraphOperationStatus> connectToProperty(PropertyValueData propValueData, PropertyDefinition propertyDefinition) {
388 Either<PropertyData, JanusGraphOperationStatus> dataTypesRes = janusGraphGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Property),
389 propertyDefinition.getUniqueId(), PropertyData.class);
391 Map<String, Object> properties = new HashMap<>();
392 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), propertyDefinition.getName());
394 return dataTypesRes.left()
395 .bind(propertyData -> janusGraphGenericDao
396 .createRelation(propValueData, propertyData, GraphEdgeLabels.PROPERTY_IMPL, properties));
400 private CapabilityData buildCapabilityData(CapabilityDefinition capabilityDefinition, String ctUniqueId) {
402 CapabilityData capabilityData = new CapabilityData(capabilityDefinition);
404 capabilityData.setUniqueId(ctUniqueId);
405 Long creationDate = capabilityData.getCreationTime();
406 if (creationDate == null) {
407 creationDate = System.currentTimeMillis();
409 capabilityData.setCreationTime(creationDate);
410 capabilityData.setModificationTime(creationDate);
411 return capabilityData;
415 public StorageOperationStatus deleteCapability(CapabilityDefinition capabilityDef) {
417 return janusGraphGenericDao
418 .deleteChildrenNodes(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), capabilityDef.getUniqueId(), GraphEdgeLabels.PROPERTY_VALUE,
419 NodeTypeEnum.PropertyValue, PropertyValueData.class)
421 .bind(props -> janusGraphGenericDao
422 .deleteNode(new CapabilityData(capabilityDef), CapabilityData.class))
424 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus)
426 .on(capData -> StorageOperationStatus.OK);